compiler:
- clang
- gcc
+env:
+ global:
+ - PANIC_ACTION="gdb -batch -x raddb/panic.gdb %e %p 1>&0 2>&0"
+ - secure: "H+uQeyOgsIyXtIPPG2VzAG8S/8KYGHlHaWhdiNuz1LM3SMcEKoPqG6o/P+HO8HVvYnA6nelyGuEryV90UfuwGY9YC6A/pqPQvx/gXSso63Zt66XSaiZjulCSm9OV8EB3wyWF7VSQ/ZHcn+L01hIlsQXTqLprMaC33cM0FYPr9fY="
+ matrix:
+ - LIBS_OPTIONAL=no LIBS_SHARED=yes
+ - LIBS_OPTIONAL=yes LIBS_SHARED=yes
+ - LIBS_OPTIONAL=yes LIBS_SHARED=yes BUILD_CFLAGS="-O2 -g3"
+addons:
+ coverity_scan:
+ project:
+ name: FreeRADIUS/freeradius-server
+ version: v3.0.x
+ description: The FreeRADIUS server project
+ notification_email: freeradius-devel@lists.freeradius.org
+ build_command_prepend: ./configure
+ build_command: make
+ branch_pattern: coverity_scan
before_install:
+ - $CC --version
+ - wget -O - http://packages.couchbase.com/ubuntu/couchbase.key | sudo apt-key add -
+ - sudo sudo wget -O /etc/apt/sources.list.d/couchbase.list http://packages.couchbase.com/ubuntu/couchbase-ubuntu1204.list
- sudo apt-get update -qq
- - sudo apt-get install -qq libtalloc-dev libssl-dev
- - sudo apt-get install -qq gdb
- - sudo apt-get install -qq build-essential autoconf dh-make debhelper devscripts fakeroot lintian pbuilder quilt
+ - >
+ sudo apt-get install --no-install-recommends -qq
+ autoconf
+ build-essential
+ debhelper
+ devscripts
+ dh-make
+ fakeroot
+ gdb
+ lintian
+ pbuilder
+ python-dev
+ quilt
+ libruby
+ ruby-dev
+ libcollectdclient-dev
+ firebird-dev
+ freetds-dev
+ libcouchbase2-libevent
+ libcouchbase-dev
+ libcurl4-openssl-dev
+ libgdbm-dev
+ libhiredis-dev
+ libidn11-dev
+ libiodbc2-dev libiodbc2
+ libjson0
+ libjson0-dev
+ libkrb5-dev
+ libldap2-dev
+ libpam0g-dev
+ libpcap-dev
+ libpcre3-dev
+ libperl-dev
+ libpq-dev
+ libreadline-dev
+ libsnmp-dev
+ libssl-dev
+ libtalloc-dev
+ libtalloc2-dbg
+ libunbound-dev
+ libykclient-dev
+ libyubikey-dev
- sudo apt-get install -qq -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" libmysqlclient-dev
- - sudo apt-get install -qq libkrb5-dev libgdbm-dev libhiredis-dev libldap2-dev libpam0g-dev libpcap-dev libpcre3-dev libperl-dev
- - sudo apt-get install -qq libpq-dev libreadline-dev libsnmp-dev
- - sudo apt-get install -qq libiodbc2 libiodbc2-dev
- - sudo apt-get install -qq libidn11-dev libyubikey-dev libykclient-dev
- - sudo apt-get install -qq firebird-dev freetds-dev python-dev ruby-dev
-env:
- - LIBS_OPTIONAL=no LIBS_SHARED=yes
- - LIBS_OPTIONAL=yes LIBS_SHARED=yes
before_script:
- - ./configure -C --enable-werror --prefix=$HOME/travis --with-shared-libs=$LIBS_SHARED --with-threads=$LIBS_OPTIONAL --with-udpfromto=$LIBS_OPTIONAL --with-openssl=$LIBS_OPTIONAL
+ - CFLAGS="${BUILD_CFLAGS}" ./configure -C --enable-werror --prefix=$HOME/freeradius --with-shared-libs=$LIBS_SHARED --with-threads=$LIBS_OPTIONAL --with-udpfromto=$LIBS_OPTIONAL --with-openssl=$LIBS_OPTIONAL
- make
-script: make travis-test
+script: if [ ${COVERITY_SCAN_BRANCH} != 1 ]; then make travis-test; fi
docdir = @docdir@
mandir = @mandir@
datadir = @datadir@
-dictdir = $(datadir)/freeradius
+dictdir = @dictdir@
logdir = @logdir@
includedir = @includedir@
CC = @CC@
RANLIB = @RANLIB@
-IMACROS = -imacros ${top_srcdir}/src/freeradius-devel/build.h -imacros ${top_srcdir}/src/freeradius-devel/autoconf.h -imacros ${top_srcdir}/src/freeradius-devel/features.h
-INCLUDE = -I${top_srcdir} -I${top_srcdir}/src
-CFLAGS = $(IMACROS) $(INCLUDE) -std=c99 -fno-strict-aliasing @CFLAGS@
+INCLUDE = -I${top_srcdir} -I${top_srcdir}/src \
+ -include ${top_srcdir}/src/freeradius-devel/autoconf.h \
+ -include ${top_srcdir}/src/freeradius-devel/build.h \
+ -include ${top_srcdir}/src/freeradius-devel/features.h \
+ -include ${top_srcdir}/src/freeradius-devel/radpaths.h
+CFLAGS = $(INCLUDE) -std=c99 -fno-strict-aliasing @CFLAGS@
CPPFLAGS = @CPPFLAGS@
LIBPREFIX = @LIBPREFIX@
EXEEXT = @EXEEXT@
INSTALL_DATA = ${INSTALL} -m 644
INSTALL_SCRIPT = ${INSTALL_PROGRAM}
INSTALLSTRIP = @INSTALLSTRIP@
-DARWIN_CFLAGS = @DARWIN_CFLAGS@
+
+#
+# Linker arguments for libraries searched for by the main
+# configure script.
+#
+TALLOC_LIBS = @TALLOC_LIBS@
+TALLOC_LDFLAGS = @TALLOC_LDFLAGS@
+
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+
+PCAP_LIBS = @PCAP_LIBS@
+PCAP_LDFLAGS = @PCAP_LDFLAGS@
+
+COLLECTDC_LIBS = @COLLECTDC_LIBS@
+COLLECTDC_LDFLAGS = @COLLECTDC_LDFLAGS@
LCRYPT = @CRYPTLIB@
-LIBS = @LIBS@
-LDFLAGS = @LDFLAGS@
+
+#
+# OpenSSL libs (if used) must be linked everywhere in order for
+# the server to work properly on on all platforms.
+#
+LIBS = $(OPENSSL_LIBS) $(TALLOC_LIBS) @LIBS@
+LDFLAGS = $(OPENSSL_LDFLAGS) $(TALLOC_LDFLAGS) @LDFLAGS@
LOGDIR = ${logdir}
RADDBDIR = ${raddbdir}
RUNDIR = ${localstatedir}/run/radiusd
SBINDIR = ${sbindir}
RADIR = ${radacctdir}
-LIBRADIUS = $(top_builddir)/src/lib/$(LIBPREFIX)freeradius-radius.la -ltalloc
+LIBRADIUS = $(top_builddir)/src/lib/$(LIBPREFIX)freeradius-radius.la $(TALLOC_LIBS)
USE_SHARED_LIBS = @USE_SHARED_LIBS@
bm_shared_libs = @USE_SHARED_LIBS@
bm_static_libs = @USE_STATIC_LIBS@
STATIC_MODULES = @STATIC_MODULES@
-
-OPENSSL_LIBS = @OPENSSL_LIBS@
-OPENSSL_INCLUDE = @OPENSSL_INCLUDE@
-
-#
-# If the system has OpenSSL, use it's version of MD4/MD5/SHA1, instead of
-# using ours.
-#
-ifneq "$(OPENSSL_INCLUDE)" ""
-CFLAGS += -DWITH_OPENSSL_MD4 -DWITH_OPENSSL_MD5
-endif
-
LIBREADLINE = @LIBREADLINE@
#
RADIUSD_VERSION_STRING = @RADIUSD_VERSION_STRING@
#
-# This allows dlopen to do runtime checks for version mistmatches
+# This allows dlopen to do runtime checks for version mismatches
# between what it was originally linked with, and the library it's
# actually loading.
#
-#LDFLAGS += -release=$(RADIUSD_VERSION_STRING)
-
MODULES = @MODULES@
HOSTINFO = @HOSTINFO@
+#
+# If the system has OpenSSL, use it's version of MD4/MD5/SHA1, instead of
+# using ours.
+#
+ifeq "$(WITH_OPENSSL)" "yes"
+CFLAGS += -DWITH_OPENSSL_MD4 -DWITH_OPENSSL_MD5
+endif
+
+OPENSSL_LIBS = @OPENSSL_LIBS@
+
ifneq ($(WITH_OPENSSL_MD5),)
LIBRADIUS_WITH_OPENSSL = 1
CFLAGS += -DWITH_OPENSSL_MD5
# http://clang.llvm.org/StaticAnalysis.html
#
-# $ make SCAN=/path/to/checker/
+# $ make SCAN=/path/to/checker/
#
ifneq ($(SCAN),)
CC := $(SCAN)/scan-build gcc -DFR_SCAN_BUILD
-LIBTOOL :=
+LIBTOOL :=
endif
#
endif
ifneq "$(LIBTOOL)" ""
-COMPILE.c := $(LIBTOOL) --quiet --mode=compile $(CC)
+COMPILE.c := $(LIBTOOL) --quiet --mode=compile $(CC)
LINK.lib := $(LIBTOOL) --quiet --mode=link $(CC) -rpath $(libdir) -o
LO := lo
LA := la
include scripts/boiler.mk
#
+# To work around OpenSSL issues with travis.
+#
+.PHONY:
+raddb/test.conf:
+ @echo 'security {' >> $@
+ @echo ' allow_vulnerable_openssl = yes' >> $@
+ @echo '}' >> $@
+ @echo '$$INCLUDE radiusd.conf' >> $@
+
+#
# Run "radiusd -C", looking for errors.
#
-$(BUILD_DIR)/tests/radiusd-c: ${BUILD_DIR}/bin/radiusd | build.raddb
+# Only redirect STDOUT, which should contain details of why the test failed.
+# Don't molest STDERR as this may be used to receive output from a debugger.
+$(BUILD_DIR)/tests/radiusd-c: raddb/test.conf ${BUILD_DIR}/bin/radiusd | build.raddb
@$(MAKE) -C raddb/certs
- @if ! ./build/make/jlibtool --mode=execute ./build/bin/radiusd -XCMd ./raddb -n debug -D ./share > $(BUILD_DIR)/tests/radiusd.config.log 2>&1; then \
+ @printf "radiusd -C... "
+ @if ! ./build/make/jlibtool --mode=execute ./build/bin/radiusd -XCMd ./raddb -D ./share -n test > $(BUILD_DIR)/tests/radiusd.config.log; then \
+ @rm -f raddb/test.conf; \
cat $(BUILD_DIR)/tests/radiusd.config.log; \
- echo "FAIL: radiusd -C"; \
+ echo "fail"; \
exit 1; \
fi
- @echo "OK: radiusd -C"
+ @rm -f raddb/test.conf
+ @echo "ok"
@touch $@
test: ${BUILD_DIR}/bin/radiusd ${BUILD_DIR}/bin/radclient tests.unit tests.keywords $(BUILD_DIR)/tests/radiusd-c | build.raddb
# Â Tests specifically for Travis. Â We do a LOT more than just
# Â the above tests
ifneq "$(findstring travis,${prefix})" ""
-travis-test: test
+travis-test: raddb/test.conf test
+ @./build/make/jlibtool --mode=execute ./build/bin/radiusd -xxxv -n test
+ @rm -f raddb/test.conf
@$(MAKE) install
+ @perl -p -i -e 's/allow_vulnerable_openssl = no/allow_vulnerable_openssl = yes/' ${raddbdir}/radiusd.conf
+ @${sbindir}/radiusd -XC
@$(MAKE) deb
endif
src/%all.mk: src/%all.mk.in src/%configure
@echo CONFIGURE $(dir $@)
@rm -f ./config.cache $(dir $<)/config.cache
- @cd $(dir $<) && CPPFLAGS=$(DARWIN_CFLAGS) CFLAGS=$(DARWIN_CFLAGS) ./configure $(CONFIGURE_ARGS)
+ @cd $(dir $<) && ./configure $(CONFIGURE_ARGS)
endif
.PHONY: check-includes
#
.PHONY: certs
certs:
- @cd raddb/certs && $(MAKE)
+ @$(MAKE) -C raddb/certs
######################################################################
#
warnings:
@(make clean all 2>&1) | egrep -v '^/|deprecated|^In file included|: In function| from |^HEADER|^CC|^LINK' > warnings.txt
@wc -l warnings.txt
+
+#
+# Ensure we're using tabs in the configuration files,
+# and remove trailing whitespace in source files.
+#
+.PHONY: whitespace
+whitespace:
+ @for x in $$(git ls-files raddb/ src/); do unexpand $$x > $$x.bak; cp $$x.bak $$x; rm -f $$x.bak;done
+ @perl -p -i -e 'trim' $$(git ls-files src/)
The FreeRADIUS server
=====================
-0. BRANCH STATE
----------------
-|BuildStatus|_
+|BuildStatus|_ |CoverityStatus|_
-.. |BuildStatus| image:: https://travis-ci.org/FreeRADIUS/freeradius-server.png?branch=v3.0.x
-.. _BuildStatus: https://travis-ci.org/FreeRADIUS/freeradius-server
+.. contents::
+ :local:
-1. INTRODUCTION
----------------
+Introduction
+------------
The FreeRADIUS Server Project is a high performance and highly
configurable RADIUS server that is available under the terms of the
more information.
-2. INSTALLATION
----------------
+Installation
+------------
To install the server, please see the INSTALL file in this directory.
-3. DEBUGGING THE SERVER
------------------------
+Debugging the Server
+--------------------
Run the server in debugging mode, (``radiusd -X``) and READ the output.
We cannot emphasize this point strongly enough. The vast majority of
discussions about common problems and solution.
-4. ADDITIONAL INFORMATION
--------------------------
+Additional Information
+----------------------
See ``doc/README`` for more information about FreeRADIUS.
http://www.amazon.com/exec/obidos/ASIN/0596003226/freeradiusorg-20/
-For other RADIUS information, the Livington internet site had a lot
-of information about radius online. Unfortunately Livingston, and the
-site, don't exist anymore but there is a copy of the site still at:
-
-http://portmasters.com/www.livingston.com/
-
-Especially worth reading is the "RADIUS for Unix administrators guide"
-
-* HTML: http://portmasters.com/tech/docs/radius/1185title.html
-* PDF: http://portmasters.com/tech/docs/pdf/radius.pdf
-
-
-5. PROBLEMS AND CONCERNS
-------------------------
+Problems and Concerns
+---------------------
We understand that the server may be difficult to configure,
install, or administer. It is, after all, a complex system with many
2. Save a copy of the default configuration: It WORKS. Don't change it!
3. Verify that the server starts. (You ARE using debugging mode, right?)
4. Send it test packets using "radclient", or a NAS or AP.
-5. Verify that the server does what you expect.
- - If it does not work, change the configuration, and go to step (3)
- If you're stuck, revert to using the "last working" configuration.
- - If it works, proceed to step (6).
+5. Verify that the server does what you expect
+ - If it does not work, change the configuration, and go to step (3)
+ - If you're stuck, revert to using the "last working" configuration.
+ - If it works, proceed to step (6).
6. Save a copy of the working configuration, along with a note of what
you changed, and why.
7. Make a SMALL change to the configuration.
frustrating than quickly making forward progress!
-6. FEEDBACK
------------
+Feedback
+--------
If you have any comments, bug reports, problems, or concerns, please
send them to the 'freeradius-users' list (see the URL above). We will
Please submit bug reports, suggestions, or patches. That feedback
gives the developers a guide as to where they should focus their work.
If you like the server, feel free to mail the list and say so.
+
+.. |CoverityStatus| image:: https://scan.coverity.com/projects/58/badge.svg?
+.. _CoverityStatus: https://scan.coverity.com/projects/58
+
+.. |BuildStatus| image:: https://travis-ci.org/FreeRADIUS/freeradius-server.png
+.. _BuildStatus: https://travis-ci.org/FreeRADIUS/freeradius-server
sm_lib_safe=`echo "$1" | sed 'y%./+-%__p_%'`
sm_func_safe=`echo "$2" | sed 'y%./+-%__p_%'`
+dnl #
+dnl # We pass all arguments for linker testing in CCPFLAGS as these
+dnl # will be passed to the compiler (then linker) first.
+dnl #
+dnl # The linker will search through -L directories in the order they
+dnl # appear on the command line. Unfortunately the same rules appear
+dnl # to apply to directories specified with --sysroot, so we must
+dnl # pass the user specified directory first.
+dnl #
+dnl # Really we should be using LDFLAGS (-L<dir>) for this.
+dnl #
old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
smart_lib=
+smart_ldflags=
smart_lib_dir=
dnl #
if test "x$smart_try_dir" != "x"; then
for try in $smart_try_dir; do
AC_MSG_CHECKING([for $2 in -l$1 in $try])
- LIBS="-L$try -l$1 $old_LIBS -Wl,-rpath,$try"
+ LIBS="-l$1 $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
AC_TRY_LINK([extern char $2();],
[$2()],
[
- smart_lib="-L$try -l$1 -Wl,-rpath,$try"
+ smart_lib="-l$1"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
AC_MSG_RESULT(yes)
break
],
[AC_MSG_RESULT(no)])
done
LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
dnl #
for try in $smart_lib_dir /usr/local/lib /opt/lib; do
AC_MSG_CHECKING([for $2 in -l$1 in $try])
- LIBS="-L$try -l$1 $old_LIBS -Wl,-rpath,$try"
+ LIBS="-l$1 $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
AC_TRY_LINK([extern char $2();],
[$2()],
[
- smart_lib="-L$try -l$1 -Wl,-rpath,$try"
+ smart_lib="-l$1"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
AC_MSG_RESULT(yes)
break
],
[AC_MSG_RESULT(no)])
done
LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
dnl #
dnl #
if test "x$smart_lib" != "x"; then
eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
- LIBS="$smart_lib $old_LIBS"
- SMART_LIBS="$smart_lib $SMART_LIBS"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
fi
])
AC_DEFUN([FR_SMART_CHECK_INCLUDE], [
ac_safe=`echo "$1" | sed 'y%./+-%__pm%'`
-old_CFLAGS="$CFLAGS"
+old_CPPFLAGS="$CPPFLAGS"
smart_include=
smart_include_dir=
if test "x$smart_try_dir" != "x"; then
for try in $smart_try_dir; do
AC_MSG_CHECKING([for $1 in $try])
- CFLAGS="$old_CFLAGS -isystem $try"
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
AC_TRY_COMPILE([$2
#include <$1>],
[int a = 1;],
AC_MSG_RESULT(no)
])
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
dnl #
FR_LOCATE_DIR(smart_include_dir,$1)
for try in $smart_include_dir /usr/local/include /opt/include; do
AC_MSG_CHECKING([for $1 in $try])
- CFLAGS="$old_CFLAGS -isystem $try"
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
AC_TRY_COMPILE([$2
#include <$1>],
[int a = 1;],
AC_MSG_RESULT(no)
])
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
dnl #
dnl #
if test "x$smart_include" != "x"; then
eval "ac_cv_header_$ac_safe=yes"
- CFLAGS="$old_CFLAGS $smart_include"
- SMART_CFLAGS="$SMART_CFLAGS $smart_include"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
fi
])
AC_OUTPUT([$1],[$2],[$3])
])
-
-# See if the compilation works with __thread, for thread-local storage
-#
+dnl #
+dnl # Figure out which storage class specifier for Thread Local Storage is supported by the compiler
+dnl #
AC_DEFUN([FR_TLS],
[
+dnl #
+dnl # See if the compilation works with __thread, for thread-local storage
+dnl #
AC_MSG_CHECKING(for __thread support in compiler)
AC_RUN_IFELSE(
[AC_LANG_SOURCE(
],[have_tls=yes],[have_tls=no],[have_tls=no])
AC_MSG_RESULT($have_tls)
if test "x$have_tls" = "xyes"; then
- AC_DEFINE([HAVE_THREAD_TLS],[1],[Define if the compiler supports __thread])
+ AC_DEFINE([TLS_STORAGE_CLASS],[__thread],[Define if the compiler supports a thread local storage class])
fi
-])
+dnl #
+dnl # __declspec(thread) does exactly the same thing as __thread, but is supported by MSVS
+dnl #
+ if test "x$have_tls" = "xno"; then
+ AC_MSG_CHECKING(for __declspec(thread) support in compiler)
+ AC_RUN_IFELSE(
+ [AC_LANG_SOURCE(
+ [[
+ static _Thread_local int val;
+ int main(int argc, char **argv) {
+ val = 0;
+ return val;
+ }
+ ]])
+ ],[have_tls=yes],[have_tls=no],[have_tls=no])
+ AC_MSG_RESULT($have_tls)
+ if test "x$have_tls" = "xyes"; then
+ AC_DEFINE([TLS_STORAGE_CLASS],[__declspec(thread)],[Define if the compiler supports a thread local storage class])
+ fi
+ fi
+dnl #
+dnl # _Thread_local does exactly the same thing as __thread, but it's standards compliant with C11.
+dnl # we, however, state we are only compliant with C99, so the compiler will probably emit warnings
+dnl # if we use it. So save it as a last resort.
+dnl #
+ if test "x$have_tls" = "xno"; then
+ AC_MSG_CHECKING(for _Thread_local support in compiler)
+ AC_RUN_IFELSE(
+ [AC_LANG_SOURCE(
+ [[
+ static _Thread_local int val;
+ int main(int argc, char **argv) {
+ val = 0;
+ return val;
+ }
+ ]])
+ ],[have_tls=yes],[have_tls=no],[have_tls=no])
+ AC_MSG_RESULT($have_tls)
+ if test "x$have_tls" = "xyes"; then
+ AC_DEFINE([TLS_STORAGE_CLASS],[_Thread_local],[Define if the compiler supports a thread local storage class])
+ fi
+ fi
+])
AC_DEFUN([VL_LIB_READLINE], [
AC_CACHE_CHECK([for a readline compatible library],
AC_SUBST(LIBREADLINE)
])dnl
+dnl #
+dnl # Figure out which storage class specifier for Thread Local Storage is supported by the compiler
+dnl #
+AC_DEFUN([FR_HAVE_BUILTIN_CHOOSE_EXPR],
+[
+dnl #
+dnl # See if the compilation works with __thread, for thread-local storage
+dnl #
+ AC_MSG_CHECKING(for __builtin_choose_expr support in compiler)
+ AC_RUN_IFELSE(
+ [AC_LANG_SOURCE(
+ [[
+ int main(int argc, char **argv) {
+ return __builtin_choose_expr(0, 1, 0);
+ }
+ ]])
+ ],[have_builtin=yes],[have_builtin=no],[have_builtin=no])
+ AC_MSG_RESULT($have_builtin)
+ if test "x$have_builtin" = "xyes"; then
+ AC_DEFINE([HAVE_BUILTIN_CHOOSE_EXPR],1,[Define if the compiler supports __builtin_choose_expr])
+ fi
+])
+
+dnl #
+dnl # Figure out which storage class specifier for Thread Local Storage is supported by the compiler
+dnl #
+AC_DEFUN([FR_HAVE_BUILTIN_TYPES_COMPATIBLE_P],
+[
+dnl #
+dnl # See if the compilation works with __thread, for thread-local storage
+dnl #
+ AC_MSG_CHECKING(for __builtin_types_compatible_p support in compiler)
+ AC_RUN_IFELSE(
+ [AC_LANG_SOURCE(
+ [[
+ int main(int argc, char **argv) {
+ return !(__builtin_types_compatible_p(char *, char *));
+ }
+ ]])
+ ],[have_builtin=yes],[have_builtin=no],[have_builtin=no])
+ AC_MSG_RESULT($have_builtin)
+ if test "x$have_builtin" = "xyes"; then
+ AC_DEFINE([HAVE_BUILTIN_TYPES_COMPATIBLE_P],1,[Define if the compiler supports __builtin_types_compatible_p])
+ fi
+])
+
AC_INCLUDE(aclocal.m4)
REGEX
CRYPTLIB
LIBPREFIX
+COLLECTDC_LDFLAGS
+COLLECTDC_LIBS
+PCAP_LDFLAGS
PCAP_LIBS
+OPENSSL_LDFLAGS
OPENSSL_LIBS
-OPENSSL_INCLUDE
LIBREADLINE
+TALLOC_LDFLAGS
+TALLOC_LIBS
DIRNAME
LOCATE
AUTOHEADER
SNMPGET
PERL
modconfdir
+dictdir
raddbdir
radacctdir
logdir
LDFLAGS
CFLAGS
CC
-DARWIN_CFLAGS
-XCODEBUILD
-SW_VERS
target_os
target_vendor
target_cpu
with_logdir
with_radacctdir
with_raddbdir
+with_dictdir
with_ascend_binary
with_threads
with_tcp
with_modules
with_experimental_modules
with_udpfromto
-with_openssl
-with_openssl_includes
-with_openssl_libraries
with_rlm_FOO_lib_dir
with_rlm_FOO_include_dir
-with_talloc_include_dir
+with_openssl
+with_openssl_lib_dir
+with_openssl_include_dir
with_talloc_lib_dir
-with_pcap_include_dir
+with_talloc_include_dir
with_pcap_lib_dir
-with_rlm_pcre_lib_dir
-with_rlm_pcre_include_dir
+with_pcap_include_dir
+with_collectdclient_lib_dir
+with_collectdclient_include_dir
+with_execinfo_lib_dir
+with_execinfo_include_dir
+with_pcre_lib_dir
+with_pcre_include_dir
'
ac_precious_vars='build_alias
host_alias
--with-logdir=DIR directory for logfiles LOCALSTATEDIR/log/radius
--with-radacctdir=DIR directory for detail files LOGDIR/radacct
--with-raddbdir=DIR directory for config files SYSCONFDIR/raddb
+ --with-dictdir=DIR directory for dictionary files DATAROOTDIR/freeradius
--with-ascend-binary include support for Ascend binary filter attributes (default=yes)
--with-threads use threads, if available. (default=yes)
--with-tcp compile in TCP support. (default=yes)
--with-vmps compile in VMPS support. (default=yes)
--with-dhcp compile in DHCP support. (default=yes)
--with-static-modules=QUOTED-MODULE-LIST
- --with-shared-libs build dynamic libraries and link against them. (default=yes)
+ --with-shared-libs build dynamic libraries and link against them.
+ (default=yes)
--with-modules=QUOTED-MODULE-LIST
- --with-experimental-modules use experimental and unstable modules. (default=no, unless --enable-developer=yes)
- --with-udpfromto compile in UDPFROMTO support. (default=yes)
- --with-openssl use OpenSSL. (default=yes)
- --with-openssl-includes=DIR directory to look for OpenSSL include files in
- --with-openssl-libraries=DIR directory to look for OpenSSL library files in
- --with-rlm-FOO-lib-dir=DIR directory to look for library files used by module FOO in
- --with-rlm-FOO-include-dir=DIR directory to look for include files used by module FOO in
- --with-talloc-include-dir=DIR directory to look for talloc include files in
- --with-talloc-lib-dir=DIR directory to look for talloc library files in
- --with-pcap-include-dir=DIR directory to look for pcap include files in
- --with-pcap-lib-dir=DIR directory to look for pcap library files in
- --with-pcre-lib-dir=DIR directory to look for PCRE library files in
- --with-pcre-include-dir=DIR directory to look for PCRE include files in
+ --with-experimental-modules
+ use experimental and unstable modules. (default=no,
+ unless --enable-developer=yes)
+ --with-udpfromto compile in UDPFROMTO support. (default=yes)
+ --with-rlm-FOO-lib-dir=DIR
+ directory in which to look for library files used by
+ module FOO
+ --with-rlm-FOO-include-dir=DIR
+ directory in which to look for include files used by
+ module FOO
+ --with-openssl use OpenSSL. (default=yes)
+ --with-openssl-lib-dir=DIR
+ directory to look for OpenSSL library files
+ --with-openssl-include-dir=DIR
+ directory to look for OpenSSL include files
+ --with-talloc-lib-dir=DIR
+ directory in which to look for talloc library files
+ --with-talloc-include-dir=DIR
+ directory in which to look for talloc include files
+ --with-pcap-lib-dir=DIR directory in which to look for pcap library files
+ --with-pcap-include-dir=DIR
+ directory in which to look for pcap include files
+ --with-collectdclient-lib-dir=DIR
+ directory in which to look for collectdclient
+ library files
+ --with-collectdclient-include-dir=DIR
+ directory in which to look for collectdclient
+ include files
+ --with-execinfo-lib-dir=DIR
+ directory in which to look for execinfo library
+ files
+ --with-execinfo-include-dir=DIR
+ directory in which to look for execinfo include
+ files
+ --with-pcre-lib-dir=DIR directory in which to look for pcre library files
+ --with-pcre-include-dir=DIR
+ directory in which to look for pcre include files
Some influential environment variables:
CC C compiler command
} # ac_fn_c_try_link
-# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
-# -------------------------------------------
-# Tests whether TYPE exists after having included INCLUDES, setting cache
-# variable VAR accordingly.
-ac_fn_c_check_type ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- eval "$3=no"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$4
-int
-main ()
-{
-if (sizeof ($2))
- return 0;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$4
-int
-main ()
-{
-if (sizeof (($2)))
- return 0;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-
-else
- eval "$3=yes"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-eval ac_res=\$$3
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_type
-
# ac_fn_c_check_func LINENO FUNC VAR
# ----------------------------------
# Tests whether FUNC exists, setting the cache variable VAR accordingly
} # ac_fn_c_check_func
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=no"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ eval "$3=yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_type
+
# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
# ---------------------------------------------
# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
program_prefix=${target_alias}-
-case "$host" in
- *-darwin*)
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking if cc is apple llvm" >&5
-$as_echo_n "checking if cc is apple llvm... " >&6; }
- if ! $CC --version 2>&1 | grep -I 'Apple LLVM' > /dev/null; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- # Extract the first word of "sw_vers", so it can be a program name with args.
-set dummy sw_vers; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_SW_VERS+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$SW_VERS"; then
- ac_cv_prog_SW_VERS="$SW_VERS" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_SW_VERS="yes"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
- test -z "$ac_cv_prog_SW_VERS" && ac_cv_prog_SW_VERS="no"
-fi
-fi
-SW_VERS=$ac_cv_prog_SW_VERS
-if test -n "$SW_VERS"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SW_VERS" >&5
-$as_echo "$SW_VERS" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
- # Extract the first word of "xcodebuild", so it can be a program name with args.
-set dummy xcodebuild; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_XCODEBUILD+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$XCODEBUILD"; then
- ac_cv_prog_XCODEBUILD="$XCODEBUILD" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_XCODEBUILD="yes"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
- test -z "$ac_cv_prog_XCODEBUILD" && ac_cv_prog_XCODEBUILD="no"
-fi
-fi
-XCODEBUILD=$ac_cv_prog_XCODEBUILD
-if test -n "$XCODEBUILD"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XCODEBUILD" >&5
-$as_echo "$XCODEBUILD" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-
- if test "x$SW_VERS" = "xyes" && test "x$XCODEBUILD" = "xyes"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: determining OSX SDK path" >&5
-$as_echo "$as_me: determining OSX SDK path" >&6;}
- osx_sdk_path=$(xcodebuild -version -sdk macosx$(sw_vers -productVersion | egrep -o '^[0-9]+\.[0-9]+') Path)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $osx_sdk_path" >&5
-$as_echo "$osx_sdk_path" >&6; }
-
- export CFLAGS="$CFLAGS --sysroot=$osx_sdk_path"
- export CPPFLAGS="$CPPFLAGS --sysroot=$osx_sdk_path"
- export LDFLAGS="$LDFLAGS -L$osx_sdk_path/usr/lib/"
- DARWIN_CFLAGS="--sysroot=$osx_sdk_path"
-
- fi
- else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
- fi
- ;;
-esac
-
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
$as_echo "$ac_cv_c_bigendian" >&6; }
case $ac_cv_c_bigendian in #(
yes)
- $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h
+
+$as_echo "#define BIG_ENDIAN 1" >>confdefs.h
;; #(
no)
- ;; #(
+
+$as_echo "#define LITTLE_ENDIAN 1" >>confdefs.h
+
+ ;; #(
universal)
$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $raddbdir" >&5
$as_echo "$raddbdir" >&6; }
+dictdir='${datarootdir}/freeradius'
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dictdir" >&5
+$as_echo_n "checking dictdir... " >&6; }
+
+# Check whether --with-dictdir was given.
+if test "${with_dictdir+set}" = set; then :
+ withval=$with_dictdir; case "$withval" in
+ no)
+ as_fn_error $? "Need dictdir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ [\\/$]* | ?:[\\/]* )
+ dictdir="$withval"
+ ;;
+ *)
+ as_fn_error $? "expected an absolute directory name for --with-dictdir: $withval" "$LINENO" 5
+ ;;
+ esac
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dictdir" >&5
+$as_echo "$dictdir" >&6; }
+
modconfdir='${raddbdir}/mods-config'
fi
-WITH_OPENSSL=yes
-# Check whether --with-openssl was given.
-if test "${with_openssl+set}" = set; then :
- withval=$with_openssl; case "$withval" in
- no)
- WITH_OPENSSL=no
- ;;
+
+# Check whether --with-rlm-FOO-lib-dir was given.
+if test "${with_rlm_FOO_lib_dir+set}" = set; then :
+ withval=$with_rlm_FOO_lib_dir; case "$withval" in
*)
- WITH_OPENSSL=yes
;;
esac
fi
-OPENSSL_INCLUDE_DIR=
-# Check whether --with-openssl-includes was given.
-if test "${with_openssl_includes+set}" = set; then :
- withval=$with_openssl_includes; case "$withval" in
- *) OPENSSL_INCLUDE_DIR="$withval"
+# Check whether --with-rlm-FOO-include-dir was given.
+if test "${with_rlm_FOO_include_dir+set}" = set; then :
+ withval=$with_rlm_FOO_include_dir; case "$withval" in
+ *)
;;
esac
fi
-OPENSSL_LIB_DIR=
+WITH_OPENSSL=yes
-# Check whether --with-openssl-libraries was given.
-if test "${with_openssl_libraries+set}" = set; then :
- withval=$with_openssl_libraries; case "$withval" in
- *) OPENSSL_LIB_DIR="$withval"
+# Check whether --with-openssl was given.
+if test "${with_openssl+set}" = set; then :
+ withval=$with_openssl; case "$withval" in
+ no)
+ WITH_OPENSSL=no
+ ;;
+ *)
+ WITH_OPENSSL=yes
;;
esac
fi
+openssl_lib_dir=
-
-# Check whether --with-rlm-FOO-lib-dir was given.
-if test "${with_rlm_FOO_lib_dir+set}" = set; then :
- withval=$with_rlm_FOO_lib_dir; case "$withval" in
- *)
+# Check whether --with-openssl-lib-dir was given.
+if test "${with_openssl_lib_dir+set}" = set; then :
+ withval=$with_openssl_lib_dir; case "$withval" in
+ *) openssl_lib_dir="$withval"
;;
esac
fi
+openssl_include_dir=
-# Check whether --with-rlm-FOO-include-dir was given.
-if test "${with_rlm_FOO_include_dir+set}" = set; then :
- withval=$with_rlm_FOO_include_dir; case "$withval" in
- *)
+# Check whether --with-openssl-include-dir was given.
+if test "${with_openssl_include_dir+set}" = set; then :
+ withval=$with_openssl_include_dir; case "$withval" in
+ *) openssl_include_dir="$withval"
;;
esac
-old_CFLAGS=$CFLAGS
-if test "x$WITH_THREADS" = "xyes"; then
- if test $ac_cv_prog_suncc = "yes"; then
- CFLAGS="$CFLAGS -mt"
- fi
-
- for ac_header in pthread.h
-do :
- ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default"
-if test "x$ac_cv_header_pthread_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_PTHREAD_H 1
-_ACEOF
-
-else
- WITH_THREADS="no"
-fi
-
-done
-
+talloc_lib_dir=
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
-$as_echo_n "checking for pthread_create in -lpthread... " >&6; }
+# Check whether --with-talloc-lib-dir was given.
+if test "${with_talloc_lib_dir+set}" = set; then :
+ withval=$with_talloc_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need talloc-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ talloc_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+talloc_include_dir=
+
+# Check whether --with-talloc-include-dir was given.
+if test "${with_talloc_include_dir+set}" = set; then :
+ withval=$with_talloc_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need talloc-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ talloc_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+smart_try_dir="$talloc_lib_dir"
+
+
+sm_lib_safe=`echo "talloc" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "_talloc" | 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 _talloc in -ltalloc in $try" >&5
+$as_echo_n "checking for _talloc in -ltalloc in $try... " >&6; }
+ LIBS="-ltalloc $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char _talloc();
+int
+main ()
+{
+_talloc()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ltalloc"
+ 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 _talloc in -ltalloc" >&5
+$as_echo_n "checking for _talloc in -ltalloc... " >&6; }
+ LIBS="-ltalloc $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char _talloc();
+int
+main ()
+{
+_talloc()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ltalloc"
+ { $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=libtalloc${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=libtalloc.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 _talloc in -ltalloc in $try" >&5
+$as_echo_n "checking for _talloc in -ltalloc in $try... " >&6; }
+ LIBS="-ltalloc $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char _talloc();
+int
+main ()
+{
+_talloc()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ltalloc"
+ 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_talloc__talloc" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: talloc library not found. Use --with-talloc-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: talloc library not found. Use --with-talloc-lib-dir=<path>." >&2;}
+ as_fn_error $? "FreeRADIUS requires libtalloc" "$LINENO" 5
+fi
+
+TALLOC_LIBS="${smart_lib}"
+TALLOC_LDFLAGS="${smart_ldflags}"
+
+
+LIBS="$old_LIBS"
+
+old_CFLAGS=$CFLAGS
+if test "x$WITH_THREADS" = "xyes"; then
+ if test $ac_cv_prog_suncc = "yes"; then
+ CFLAGS="$CFLAGS -mt"
+ fi
+
+ for ac_header in pthread.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default"
+if test "x$ac_cv_header_pthread_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_PTHREAD_H 1
+_ACEOF
+
+else
+
+ WITH_THREADS="no"
+ fail=pthread.h
+
+fi
+
+done
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
+$as_echo_n "checking for pthread_create in -lpthread... " >&6; }
if ${ac_cv_lib_pthread_pthread_create+:} false; then :
$as_echo_n "(cached) " >&6
else
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5
$as_echo_n "checking for pthread_create in -lc_r... " >&6; }
if ${ac_cv_lib_c_r_pthread_create+:} false; then :
$as_echo_n "(cached) " >&6
if test "x$ac_cv_lib_c_r_pthread_create" = xyes; then :
CFLAGS="$CFLAGS -pthread -D_THREAD_SAFE"
else
- WITH_THREADS="no"
+
+ WITH_THREADS="no"
+ fail=-lpthread
+
fi
fi
+
+ if test "x$WITH_THREADS" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building with thread support." >&5
+$as_echo "$as_me: WARNING: silently not building with thread support." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: thread support requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: thread support requires: $fail." >&2;}
+ else
+
+$as_echo "#define WITH_THREADS 1" >>confdefs.h
+
+ fi
fi
if test "x$WITH_THREADS" != "xyes"; then
fi
-if test "x$WITH_THREADS" = "xyes"; then
-
-$as_echo "#define WITH_THREADS 1" >>confdefs.h
-
-fi
-
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
$as_echo_n "checking for dlopen in -ldl... " >&6; }
if ${ac_cv_lib_dl_dlopen+:} false; then :
fi
-smart_try_dir="$pcap_lib_dir"
+pcap_lib_dir=
+# Check whether --with-pcap-lib-dir was given.
+if test "${with_pcap_lib_dir+set}" = set; then :
+ withval=$with_pcap_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need pcap-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ pcap_lib_dir="$withval"
+ ;;
+ esac
+fi
-sm_lib_safe=`echo "pcap" | sed 'y%./+-%__p_%'`
+
+pcap_include_dir=
+
+# Check whether --with-pcap-include-dir was given.
+if test "${with_pcap_include_dir+set}" = set; then :
+ withval=$with_pcap_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need pcap-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ pcap_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+smart_try_dir="$pcap_lib_dir"
+
+
+sm_lib_safe=`echo "pcap" | sed 'y%./+-%__p_%'`
sm_func_safe=`echo "pcap_open_live" | 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 pcap_open_live in -lpcap in $try" >&5
$as_echo_n "checking for pcap_open_live in -lpcap in $try... " >&6; }
- LIBS="-L$try -lpcap $old_LIBS -Wl,-rpath,$try"
+ LIBS="-lpcap $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
extern char pcap_open_live();
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-L$try -lpcap -Wl,-rpath,$try"
+ smart_lib="-lpcap"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
break
conftest$ac_exeext conftest.$ac_ext
done
LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_lib" = "x"; then
for try in $smart_lib_dir /usr/local/lib /opt/lib; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_open_live in -lpcap in $try" >&5
$as_echo_n "checking for pcap_open_live in -lpcap in $try... " >&6; }
- LIBS="-L$try -lpcap $old_LIBS -Wl,-rpath,$try"
+ LIBS="-lpcap $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
extern char pcap_open_live();
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-L$try -lpcap -Wl,-rpath,$try"
+ smart_lib="-lpcap"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
break
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_lib $old_LIBS"
- SMART_LIBS="$smart_lib $SMART_LIBS"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
fi
if test "x$ac_cv_lib_pcap_pcap_open_live" != "xyes"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: pcap library not found. Use --with-pcap-lib-dir=<path>." >&5
-$as_echo "$as_me: WARNING: pcap library not found. Use --with-pcap-lib-dir=<path>." >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: pcap library not found, silently disabling the RADIUS sniffer and ARP listener." >&5
-$as_echo "$as_me: WARNING: pcap library not found, silently disabling the RADIUS sniffer and ARP listener." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: pcap library not found, silently disabling the RADIUS sniffer, and ARP listener. Use --with-pcap-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: pcap library not found, silently disabling the RADIUS sniffer, and ARP listener. Use --with-pcap-lib-dir=<path>." >&2;}
else
- PCAP_LIBS="${smart_lib}"
- LIBS=$old_LIBS
$as_echo "#define HAVE_LIBPCAP 1" >>confdefs.h
+
+ for ac_func in \
+ pcap_fopen_offline \
+ pcap_dump_fopen \
+ pcap_create \
+ pcap_activate
+
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+ PCAP_LIBS="${smart_lib}"
+ PCAP_LDFLAGS="${smart_ldflags}"
+fi
+LIBS="${old_LIBS}"
+
+collectdclient_lib_dir=
+
+# Check whether --with-collectdclient-lib-dir was given.
+if test "${with_collectdclient_lib_dir+set}" = set; then :
+ withval=$with_collectdclient_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need collectdclient-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ collectdclient_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+collectdclient_include_dir=
+
+# Check whether --with-collectdclient-include-dir was given.
+if test "${with_collectdclient_include_dir+set}" = set; then :
+ withval=$with_collectdclient_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need collectdclient-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ collectdclient_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+smart_try_dir="$collectdclient_lib_dir"
+
+
+sm_lib_safe=`echo "collectdclient" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "lcc_connect" | 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 lcc_connect in -lcollectdclient in $try" >&5
+$as_echo_n "checking for lcc_connect in -lcollectdclient in $try... " >&6; }
+ LIBS="-lcollectdclient $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char lcc_connect();
+int
+main ()
+{
+lcc_connect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcollectdclient"
+ 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 lcc_connect in -lcollectdclient" >&5
+$as_echo_n "checking for lcc_connect in -lcollectdclient... " >&6; }
+ LIBS="-lcollectdclient $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char lcc_connect();
+int
+main ()
+{
+lcc_connect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcollectdclient"
+ { $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=libcollectdclient${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=libcollectdclient.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 lcc_connect in -lcollectdclient in $try" >&5
+$as_echo_n "checking for lcc_connect in -lcollectdclient in $try... " >&6; }
+ LIBS="-lcollectdclient $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char lcc_connect();
+int
+main ()
+{
+lcc_connect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcollectdclient"
+ 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_collectdclient_lcc_connect" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: collectdclient library not found. Use --with-collectdclient-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: collectdclient library not found. Use --with-collectdclient-lib-dir=<path>." >&2;}
+else
+ COLLECTDC_LIBS="${smart_lib}"
+ COLLECTDC_LDFLAGS="${smart_ldflags}"
fi
+LIBS="${old_LIBS}"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a readline compatible library" >&5
-case "$host" in
- *-interix*)
- CFLAGS="$CFLAGS -D_ALL_SOURCE"
- ;;
- *-darwin*)
- CFLAGS="$CFLAGS -DDARWIN"
- LIBS="-framework DirectoryService $LIBS"
- ;;
-esac
+smart_try_dir="$talloc_include_dir"
-ac_header_dirent=no
-for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do
- as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh`
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5
-$as_echo_n "checking for $ac_hdr that defines DIR... " >&6; }
-if eval \${$as_ac_Header+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+
+ac_safe=`echo "talloc.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
+smart_include=
+smart_include_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 talloc.h in $try" >&5
+$as_echo_n "checking for talloc.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#include <sys/types.h>
-#include <$ac_hdr>
+ #include <talloc.h>
int
main ()
{
-if ((DIR *) 0)
-return 0;
+int a = 1;
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
- eval "$as_ac_Header=yes"
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
else
- eval "$as_ac_Header=no"
+
+ 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
-eval ac_res=\$$as_ac_Header
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+
+if test "x$smart_include" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for talloc.h" >&5
+$as_echo_n "checking for talloc.h... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <talloc.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
+
+
+if test "x$LOCATE" != "x"; then
+ DIRS=
+ file=talloc.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 /usr/local/include /opt/include; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for talloc.h in $try" >&5
+$as_echo_n "checking for talloc.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <talloc.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
+
+if test "x$ac_cv_header_talloc_h" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: talloc headers not found. Use --with-talloc-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: talloc headers not found. Use --with-talloc-include-dir=<path>." >&2;}
+ as_fn_error $? "FreeRADIUS requires libtalloc" "$LINENO" 5
+fi
+
+case "$host" in
+ *-interix*)
+ CFLAGS="$CFLAGS -D_ALL_SOURCE"
+ ;;
+ *-darwin*)
+ CFLAGS="$CFLAGS -DDARWIN"
+ LIBS="-framework DirectoryService $LIBS"
+ ;;
+esac
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do
+ as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5
+$as_echo_n "checking for $ac_hdr that defines DIR... " >&6; }
+if eval \${$as_ac_Header+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <$ac_hdr>
+
+int
+main ()
+{
+if ((DIR *) 0)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$as_ac_Header=yes"
+else
+ eval "$as_ac_Header=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$as_ac_Header
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
cat >>confdefs.h <<_ACEOF
stddef.h \
fnmatch.h \
sia.h \
- siad.h
+ siad.h \
+ features.h \
+ limits.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
for ac_header in net/if.h
do :
ac_fn_c_check_header_compile "$LINENO" "net/if.h" "ac_cv_header_net_if_h" "
- #ifdef HAVE_SYS_SOCKET_H
- # include <sys/socket.h>
- #endif
+ #ifdef HAVE_SYS_SOCKET_H
+ # include <sys/socket.h>
+ #endif
+
"
if test "x$ac_cv_header_net_if_h" = xyes; then :
fi
if test "x$WITH_OPENSSL" = xyes; then
- old_LIBS=$LIBS
- old_LDFLAGS="$LDFLAGS"
+ OLD_LIBS="$LIBS"
- OPENSSL_INCLUDE="-DNO_OPENSSL"
- OPENSSL_LIBS=
- if test "x$OPENSSL_LIB_DIR" != "x"; then
- LDFLAGS="-L$OPENSSL_LIB_DIR $LDFLAGS"
- fi
+ CFLAGS="$CFLAGS -DOPENSSL_NO_KRB5"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DH_new in -lcrypto" >&5
-$as_echo_n "checking for DH_new in -lcrypto... " >&6; }
-if ${ac_cv_lib_crypto_DH_new+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lcrypto $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+ smart_try_dir="$openssl_lib_dir"
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char DH_new ();
+
+sm_lib_safe=`echo "crypto" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "DH_new" | 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 DH_new in -lcrypto in $try" >&5
+$as_echo_n "checking for DH_new in -lcrypto in $try... " >&6; }
+ LIBS="-lcrypto $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char DH_new();
int
main ()
{
-return DH_new ();
+DH_new()
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_crypto_DH_new=yes
+
+ smart_lib="-lcrypto"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
else
- ac_cv_lib_crypto_DH_new=no
+ { $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=$ac_check_lib_save_LIBS
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_DH_new" >&5
-$as_echo "$ac_cv_lib_crypto_DH_new" >&6; }
-if test "x$ac_cv_lib_crypto_DH_new" = xyes; then :
- LIBS="-lcrypto $LIBS"
+if test "x$smart_lib" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DH_new in -lcrypto" >&5
+$as_echo_n "checking for DH_new in -lcrypto... " >&6; }
+ LIBS="-lcrypto $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char DH_new();
+int
+main ()
+{
+DH_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
-$as_echo "#define HAVE_LIBCRYPTO 1" >>confdefs.h
+ smart_lib="-lcrypto"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_new in -lssl" >&5
-$as_echo_n "checking for SSL_new in -lssl... " >&6; }
-if ${ac_cv_lib_ssl_SSL_new+:} false; then :
- $as_echo_n "(cached) " >&6
else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lssl $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+ { $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
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char SSL_new ();
+if test "x$smart_lib" = "x"; then
+
+
+if test "x$LOCATE" != "x"; then
+ DIRS=
+ file=libcrypto${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=libcrypto.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 DH_new in -lcrypto in $try" >&5
+$as_echo_n "checking for DH_new in -lcrypto in $try... " >&6; }
+ LIBS="-lcrypto $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char DH_new();
+int
+main ()
+{
+DH_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcrypto"
+ 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_crypto_DH_new" = "xyes"; then
+
+$as_echo "#define HAVE_LIBCRYPTO 1" >>confdefs.h
+
+ OPENSSL_LIBS="$smart_lib"
+ OPENSSL_LDFLAGS="$smart_ldflags"
+
+
+
+sm_lib_safe=`echo "ssl" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "SSL_new" | 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 SSL_new in -lssl in $try" >&5
+$as_echo_n "checking for SSL_new in -lssl in $try... " >&6; }
+ LIBS="-lssl $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SSL_new();
+int
+main ()
+{
+SSL_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lssl"
+ 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 SSL_new in -lssl" >&5
+$as_echo_n "checking for SSL_new in -lssl... " >&6; }
+ LIBS="-lssl $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SSL_new();
+int
+main ()
+{
+SSL_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lssl"
+ { $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=libssl${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=libssl.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 SSL_new in -lssl in $try" >&5
+$as_echo_n "checking for SSL_new in -lssl in $try... " >&6; }
+ LIBS="-lssl $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SSL_new();
+int
+main ()
+{
+SSL_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lssl"
+ 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_ssl_SSL_new" != "xyes"; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed linking to libssl. Use --with-openssl-lib-dir=<path>, or --with-openssl=no (builds without OpenSSL)
+See \`config.log' for more details" "$LINENO" 5; }
+ else
+
+$as_echo "#define HAVE_LIBSSL 1" >>confdefs.h
+
+ OPENSSL_LIBS="$OPENSSL_LIBS $smart_lib"
+
+ if test "$OPENSSL_LDFLAGS" != "$smart_ldflags"; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "\"inconsistent LDFLAGS between -lssl '$smart_ldflags' and -lcrypto '$OPENSSL_LDFLAGS'\"
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed linking to libcrypto. Use --with-openssl-lib-dir=<path>, or --with-openssl=no (builds without OpenSSL)
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+
+ smart_try_dir="$openssl_include_dir"
+
+
+ac_safe=`echo "openssl/ssl.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
+smart_include=
+smart_include_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 openssl/ssl.h in $try" >&5
+$as_echo_n "checking for openssl/ssl.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <openssl/ssl.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
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ssl.h" >&5
+$as_echo_n "checking for openssl/ssl.h... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <openssl/ssl.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
+
+
+if test "x$LOCATE" != "x"; then
+ DIRS=
+ file=openssl/ssl.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 /usr/local/include /opt/include; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ssl.h in $try" >&5
+$as_echo_n "checking for openssl/ssl.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <openssl/ssl.h>
int
main ()
{
-return SSL_new ();
+int a = 1;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_ssl_SSL_new=yes
-else
- ac_cv_lib_ssl_SSL_new=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_new" >&5
-$as_echo "$ac_cv_lib_ssl_SSL_new" >&6; }
-if test "x$ac_cv_lib_ssl_SSL_new" = xyes; then :
-
-
-$as_echo "#define HAVE_LIBSSL 1" >>confdefs.h
+if ac_fn_c_try_compile "$LINENO"; then :
- if test "x$OPENSSL_LIB_DIR" != "x"; then
- OPENSSL_LIBS="-L$OPENSSL_LIB_DIR"
- fi
- OPENSSL_LIBS="$OPENSSL_LIBS -lcrypto -lssl -lcrypto"
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
else
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "failed linking to libssl
-See \`config.log' for more details" "$LINENO" 5; }
-
+ 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
+ if test "x$ac_cv_header_openssl_ssl_h" = "xyes"; then
+
+$as_echo "#define HAVE_OPENSSL_SSL_H 1" >>confdefs.h
- old_CPPFLAGS=$CPPFLAGS
- old_CFLAGS=$CFLAGS
- if test "x$OPENSSL_INCLUDE_DIR" != "x"; then
- CPPFLAGS="-isystem $OPENSSL_INCLUDE_DIR $CPPFLAGS"
- CFLAGS="-isystem $OPENSSL_INCLUDE_DIR $CFLAGS"
- fi
- CPPFLAGS="$CPPFLAGS -DOPENSSL_NO_KRB5"
- for ac_header in \
- openssl/ssl.h \
- openssl/crypto.h \
- openssl/err.h \
- openssl/evp.h \
- openssl/md5.h \
- openssl/md4.h \
- openssl/sha.h \
- openssl/ocsp.h \
- openssl/engine.h
+ for ac_header in \
+ openssl/crypto.h \
+ openssl/err.h \
+ openssl/evp.h \
+ openssl/md5.h \
+ openssl/md4.h \
+ openssl/sha.h \
+ openssl/ocsp.h \
+ openssl/engine.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
else
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "failed locating OpenSSL headers
+as_fn_error $? "failed locating OpenSSL headers. Use --with-openssl-include-dir=<path>, or --with-openssl=no (builds without OpenSSL)
See \`config.log' for more details" "$LINENO" 5; }
done
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL version >= 0.9.7" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL version >= 0.9.7" >&5
$as_echo_n "checking for OpenSSL version >= 0.9.7... " >&6; }
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <openssl/crypto.h>
- #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
- yes
- #endif
+ #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
+ yes
+ #endif
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
$EGREP "yes" >/dev/null 2>&1; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ { $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 "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "OpenSSL version too old
See \`config.log' for more details" "$LINENO" 5; }
rm -f conftest*
- if test "x$OPENSSL_INCLUDE_DIR" != "x"; then
- OPENSSL_INCLUDE="-isystem $OPENSSL_INCLUDE_DIR -DOPENSSL_NO_KRB5"
- else
- OPENSSL_INCLUDE="-DOPENSSL_NO_KRB5"
- fi
+ old_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$OPENSSL_LDFLAGS $CPPFLAGS"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking OpenSSL library and header version consistency" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking OpenSSL library and header version consistency" >&5
$as_echo_n "checking OpenSSL library and header version consistency... " >&6; }
- if test "$cross_compiling" = yes; then :
+ if test "$cross_compiling" = yes; then :
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "cannot run test program while cross compiling
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
- #include <stdio.h>
- #include <openssl/opensslv.h>
- #include <openssl/crypto.h>
+ #include <stdio.h>
+ #include <openssl/opensslv.h>
+ #include <openssl/crypto.h>
int
main ()
{
- if (SSLeay() == OPENSSL_VERSION_NUMBER) {
- return 0;
- } else {
printf("library: %lx header: %lx... ", (unsigned long) SSLeay(), (unsigned long) OPENSSL_VERSION_NUMBER);
- return 1;
- }
+ if (SSLeay() == OPENSSL_VERSION_NUMBER) {
+ return 0;
+ } else {
+ return 1;
+ }
;
_ACEOF
if ac_fn_c_try_run "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ { $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 "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "OpenSSL library version does not match header version
See \`config.log' for more details" "$LINENO" 5; }
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-
- if test "x$OPENSSL_LIBS" = x; then
- LIBS=$old_LIBS
- LDFLAGS="$old_LDFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
- if test "x$OPENSSL_INCLUDE" = x; then
- CPPFLAGS=$old_CPPFLAGS
- CFLAGS=$old_CFLAGS
- fi
-fi
+ LIBS="$OLD_LIBS"
-export OPENSSL_LIBS
+ export OPENSSL_LIBS OPENSSL_LDFLAGS
+fi
if test "x$PCAP_LIBS" = x; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: skipping test for pcap.h." >&5
$as_echo "$as_me: skipping test for pcap.h." >&6;}
else
- smart_try_dir="$pcap_include_dir"
+ smart_try_dir="$pcap_include_dir"
ac_safe=`echo "pcap.h" | sed 'y%./+-%__pm%'`
-old_CFLAGS="$CFLAGS"
+old_CPPFLAGS="$CPPFLAGS"
smart_include=
smart_include_dir=
for try in $smart_try_dir; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap.h in $try" >&5
$as_echo_n "checking for pcap.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_include" = "x"; then
for try in $smart_include_dir /usr/local/include /opt/include; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap.h in $try" >&5
$as_echo_n "checking for pcap.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_include" != "x"; then
eval "ac_cv_header_$ac_safe=yes"
- CFLAGS="$old_CFLAGS $smart_include"
- SMART_CFLAGS="$SMART_CFLAGS $smart_include"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
fi
- if test "x$ac_cv_header_pcap_h" != "xyes"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: pcap headers not found. Use --with-pcap-include-dir=<path>." >&5
-$as_echo "$as_me: WARNING: pcap headers not found. Use --with-pcap-include-dir=<path>." >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: pcap.h not found, silently disabling the RADIUS sniffer, and ARP listener." >&5
-$as_echo "$as_me: WARNING: pcap.h not found, silently disabling the RADIUS sniffer, and ARP listener." >&2;}
- else
+ if test "x$ac_cv_header_pcap_h" == "xyes"; then
$as_echo "#define HAVE_PCAP_H 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_fopen_offline in -lpcap" >&5
-$as_echo_n "checking for pcap_fopen_offline in -lpcap... " >&6; }
-if ${ac_cv_lib_pcap_pcap_fopen_offline+:} false; then :
- $as_echo_n "(cached) " >&6
+
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: pcap headers not found, silently disabling the RADIUS sniffer, and ARP listener. Use --with-pcap-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: pcap headers not found, silently disabling the RADIUS sniffer, and ARP listener. Use --with-pcap-include-dir=<path>." >&2;}
+ fi
+fi
+
+if test "x$COLLECTDC_LIBS" = x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: skipping test for collectd/client.h." >&5
+$as_echo "$as_me: skipping test for collectd/client.h." >&6;}
else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lpcap $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ smart_try_dir="$collectdclient_include_dir"
+
+
+ac_safe=`echo "collectd/client.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
+smart_include=
+smart_include_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 collectd/client.h in $try" >&5
+$as_echo_n "checking for collectd/client.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char pcap_fopen_offline ();
+ #include <collectd/client.h>
int
main ()
{
-return pcap_fopen_offline ();
+int a = 1;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_pcap_pcap_fopen_offline=yes
+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
- ac_cv_lib_pcap_pcap_fopen_offline=no
+
+ 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_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcap_pcap_fopen_offline" >&5
-$as_echo "$ac_cv_lib_pcap_pcap_fopen_offline" >&6; }
-if test "x$ac_cv_lib_pcap_pcap_fopen_offline" = xyes; then :
+if test "x$smart_include" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for collectd/client.h" >&5
+$as_echo_n "checking for collectd/client.h... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <collectd/client.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
-$as_echo "#define HAVE_PCAP_FOPEN_OFFLINE 1" >>confdefs.h
+ 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
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_dump_fopen in -lpcap" >&5
-$as_echo_n "checking for pcap_dump_fopen in -lpcap... " >&6; }
-if ${ac_cv_lib_pcap_pcap_dump_fopen+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lpcap $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+
+if test "x$LOCATE" != "x"; then
+ DIRS=
+ file=collectd/client.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 /usr/local/include /opt/include; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for collectd/client.h in $try" >&5
+$as_echo_n "checking for collectd/client.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char pcap_dump_fopen ();
+ #include <collectd/client.h>
int
main ()
{
-return pcap_dump_fopen ();
+int a = 1;
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_pcap_pcap_dump_fopen=yes
+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
- ac_cv_lib_pcap_pcap_dump_fopen=no
+
+ 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_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcap_pcap_dump_fopen" >&5
-$as_echo "$ac_cv_lib_pcap_pcap_dump_fopen" >&6; }
-if test "x$ac_cv_lib_pcap_pcap_dump_fopen" = xyes; then :
+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
-$as_echo "#define HAVE_PCAP_DUMP_FOPEN 1" >>confdefs.h
+ if test "x$ac_cv_header_collectd_client_h" == "xyes"; then
+$as_echo "#define HAVE_COLLECTDC_H 1" >>confdefs.h
-fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: collectdclient headers not found. Use --with-collectdclient-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: collectdclient headers not found. Use --with-collectdclient-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 :
if ${ac_cv_type_uint16_t+:} false; then :
$as_echo_n "(cached) " >&6
else
- ac_cv_type_uint16_t=no
+ ac_cv_type_uint16_t=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef HAVE_INTTYPES_H
+ # include <inttypes.h>
+ #endif
+
+ #ifdef HAVE_STDINT_H
+ # include <stdint.h>
+ #endif
+
+int
+main ()
+{
+uint16_t foo
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_type_uint16_t=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint16_t" >&5
+$as_echo "$ac_cv_type_uint16_t" >&6; }
+
+ if test "$ac_cv_type_uint16_t" != "yes"; then
+
+$as_echo "#define uint16_t unsigned short" >>confdefs.h
+
+ fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint32_t" >&5
+$as_echo_n "checking for uint32_t... " >&6; }
+if ${ac_cv_type_uint32_t+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_type_uint32_t=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef HAVE_INTTYPES_H
+ # include <inttypes.h>
+ #endif
+
+ #ifdef HAVE_STDINT_H
+ # include <stdint.h>
+ #endif
+
+int
+main ()
+{
+uint32_t foo
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_type_uint32_t=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint32_t" >&5
+$as_echo "$ac_cv_type_uint32_t" >&6; }
+
+ if test "$ac_cv_type_uint32_t" != "yes"; then
+
+$as_echo "#define uint32_t unsigned int" >>confdefs.h
+
+ fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint64_t" >&5
+$as_echo_n "checking for uint64_t... " >&6; }
+if ${ac_cv_type_uint64_t+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_type_uint64_t=no
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#ifdef HAVE_INTTYPES_H
int
main ()
{
-uint16_t foo
+uint64_t foo
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_type_uint16_t=yes
+ ac_cv_type_uint64_t=yes
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint16_t" >&5
-$as_echo "$ac_cv_type_uint16_t" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint64_t" >&5
+$as_echo "$ac_cv_type_uint64_t" >&6; }
- if test "$ac_cv_type_uint16_t" != "yes"; then
+ if test "$ac_cv_type_uint64_t" != "yes"; then
-$as_echo "#define uint16_t unsigned short" >>confdefs.h
+$as_echo "#define uint64_t unsigned long long" >>confdefs.h
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint32_t" >&5
-$as_echo_n "checking for uint32_t... " >&6; }
-if ${ac_cv_type_uint32_t+:} false; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sig_t" >&5
+$as_echo_n "checking for sig_t... " >&6; }
+if ${ac_cv_type_sig_t+:} false; then :
$as_echo_n "(cached) " >&6
else
- ac_cv_type_uint32_t=no
+ ac_cv_type_sig_t=no
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#ifdef HAVE_INTTYPES_H
- # include <inttypes.h>
- #endif
-
- #ifdef HAVE_STDINT_H
- # include <stdint.h>
+#ifdef HAVE_SIGNAL_H
+ # include <signal.h>
#endif
int
main ()
{
-uint32_t foo
+sig_t foo
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_type_uint32_t=yes
+ ac_cv_type_sig_t=yes
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uint32_t" >&5
-$as_echo "$ac_cv_type_uint32_t" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_sig_t" >&5
+$as_echo "$ac_cv_type_sig_t" >&6; }
- if test "$ac_cv_type_uint32_t" != "yes"; then
+ if test "$ac_cv_type_sig_t" != "yes"; then
-$as_echo "#define uint32_t unsigned int" >>confdefs.h
+$as_echo "#define sig_t void(*sig_t)(int)" >>confdefs.h
fi
+ac_fn_c_check_type "$LINENO" "__uint128_t" "ac_cv_type___uint128_t" "$ac_includes_default"
+if test "x$ac_cv_type___uint128_t" = xyes; then :
+
+$as_echo "#define HAVE___UINT128_T 1" >>confdefs.h
+
+fi
+
+
+ac_fn_c_check_type "$LINENO" "uint128_t" "ac_cv_type_uint128_t" "
+ #ifdef HAVE_INTTYPES_H
+ # include <inttypes.h>
+ #endif
+
+ #ifdef HAVE_STDINT_H
+ # include <stdint.h>
+ #endif
+
+
+"
+if test "x$ac_cv_type_uint128_t" = xyes; then :
+
+$as_echo "#define HAVE_UINT128_T 1" >>confdefs.h
+
+fi
+
+
ac_fn_c_check_type "$LINENO" "struct in6_addr" "ac_cv_type_struct_in6_addr" "
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
inet_aton \
inet_pton \
inet_ntop \
+ mallopt \
setlinebuf \
setvbuf \
getusershell \
$as_echo "#define WITH_NDEBUG 1" >>confdefs.h
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+export EXPERIMENTAL
+
+if test -d $srcdir/.git -a "x$GIT" = "xyes"; then
+ RADIUSD_VERSION_COMMIT=`git log --pretty=format:'%h' -n 1`
+
+cat >>confdefs.h <<_ACEOF
+#define RADIUSD_VERSION_COMMIT ${RADIUSD_VERSION_COMMIT}
+_ACEOF
+
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __thread support in compiler" >&5
+$as_echo_n "checking for __thread support in compiler... " >&6; }
+ if test "$cross_compiling" = yes; then :
+ have_tls=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ static __thread int val;
+ int main(int argc, char **argv) {
+ val = 0;
+ return val;
+ }
+
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ have_tls=yes
+else
+ have_tls=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_tls" >&5
+$as_echo "$have_tls" >&6; }
+ if test "x$have_tls" = "xyes"; then
+
+$as_echo "#define TLS_STORAGE_CLASS __thread" >>confdefs.h
+
+ fi
+
+ if test "x$have_tls" = "xno"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __declspec(thread) support in compiler" >&5
+$as_echo_n "checking for __declspec(thread) support in compiler... " >&6; }
+ if test "$cross_compiling" = yes; then :
+ have_tls=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ static _Thread_local int val;
+ int main(int argc, char **argv) {
+ val = 0;
+ return val;
+ }
+
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ have_tls=yes
+else
+ have_tls=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_tls" >&5
+$as_echo "$have_tls" >&6; }
+ if test "x$have_tls" = "xyes"; then
+
+$as_echo "#define TLS_STORAGE_CLASS __declspec(thread)" >>confdefs.h
+
+ fi
+ fi
+ if test "x$have_tls" = "xno"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _Thread_local support in compiler" >&5
+$as_echo_n "checking for _Thread_local support in compiler... " >&6; }
+ if test "$cross_compiling" = yes; then :
+ have_tls=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ static _Thread_local int val;
+ int main(int argc, char **argv) {
+ val = 0;
+ return val;
+ }
+
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ have_tls=yes
+else
+ have_tls=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_tls" >&5
+$as_echo "$have_tls" >&6; }
+ if test "x$have_tls" = "xyes"; then
+
+$as_echo "#define TLS_STORAGE_CLASS _Thread_local" >>confdefs.h
+
+ fi
+ fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_choose_expr support in compiler" >&5
+$as_echo_n "checking for __builtin_choose_expr support in compiler... " >&6; }
+ if test "$cross_compiling" = yes; then :
+ have_builtin=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ int main(int argc, char **argv) {
+ return __builtin_choose_expr(0, 1, 0);
+ }
+
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ have_builtin=yes
+else
+ have_builtin=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_builtin" >&5
+$as_echo "$have_builtin" >&6; }
+ if test "x$have_builtin" = "xyes"; then
+
+$as_echo "#define HAVE_BUILTIN_CHOOSE_EXPR 1" >>confdefs.h
+
+ fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_types_compatible_p support in compiler" >&5
+$as_echo_n "checking for __builtin_types_compatible_p support in compiler... " >&6; }
+ if test "$cross_compiling" = yes; then :
+ have_builtin=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ int main(int argc, char **argv) {
+ return !(__builtin_types_compatible_p(char *, char *));
+ }
+
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ have_builtin=yes
+else
+ have_builtin=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_builtin" >&5
+$as_echo "$have_builtin" >&6; }
+ if test "x$have_builtin" = "xyes"; then
+
+$as_echo "#define HAVE_BUILTIN_TYPES_COMPATIBLE_P 1" >>confdefs.h
+
+ fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for talloc_set_memlimit in -ltalloc" >&5
+$as_echo_n "checking for talloc_set_memlimit in -ltalloc... " >&6; }
+if ${ac_cv_lib_talloc_talloc_set_memlimit+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ltalloc $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char talloc_set_memlimit ();
+int
+main ()
+{
+return talloc_set_memlimit ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_talloc_talloc_set_memlimit=yes
+else
+ ac_cv_lib_talloc_talloc_set_memlimit=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_talloc_talloc_set_memlimit" >&5
+$as_echo "$ac_cv_lib_talloc_talloc_set_memlimit" >&6; }
+if test "x$ac_cv_lib_talloc_talloc_set_memlimit" = xyes; then :
+
+
+$as_echo "#define HAVE_TALLOC_SET_MEMLIMIT 1" >>confdefs.h
+
+
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for crypt in -lcrypt" >&5
+$as_echo_n "checking for crypt in -lcrypt... " >&6; }
+if ${ac_cv_lib_crypt_crypt+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypt $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char crypt ();
+int
+main ()
+{
+return crypt ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_crypt_crypt=yes
+else
+ ac_cv_lib_crypt_crypt=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypt_crypt" >&5
+$as_echo "$ac_cv_lib_crypt_crypt" >&6; }
+if test "x$ac_cv_lib_crypt_crypt" = xyes; then :
+ CRYPTLIB="-lcrypt"
+
fi
-export EXPERIMENTAL
-if test -d $srcdir/.git -a "x$GIT" = "xyes"; then
- RADIUSD_VERSION_COMMIT=`git log --pretty=format:'%h' -n 1`
+if test "$CRYPTLIB" != ""; then
-cat >>confdefs.h <<_ACEOF
-#define RADIUSD_VERSION_COMMIT "${RADIUSD_VERSION_COMMIT}"
-_ACEOF
+$as_echo "#define HAVE_CRYPT /**/" >>confdefs.h
+
+else
+ ac_fn_c_check_func "$LINENO" "crypt" "ac_cv_func_crypt"
+if test "x$ac_cv_func_crypt" = xyes; then :
+
+$as_echo "#define HAVE_CRYPT /**/" >>confdefs.h
fi
+fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __thread support in compiler" >&5
-$as_echo_n "checking for __thread support in compiler... " >&6; }
- if test "$cross_compiling" = yes; then :
- have_tls=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for setkey in -lcipher" >&5
+$as_echo_n "checking for setkey in -lcipher... " >&6; }
+if ${ac_cv_lib_cipher_setkey+:} false; then :
+ $as_echo_n "(cached) " >&6
else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcipher $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
- static __thread int val;
- int main(int argc, char **argv) {
- val = 0;
- return val;
- }
-
-
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char setkey ();
+int
+main ()
+{
+return setkey ();
+ ;
+ return 0;
+}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
- have_tls=yes
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_cipher_setkey=yes
else
- have_tls=no
+ ac_cv_lib_cipher_setkey=no
fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
- conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cipher_setkey" >&5
+$as_echo "$ac_cv_lib_cipher_setkey" >&6; }
+if test "x$ac_cv_lib_cipher_setkey" = xyes; then :
+ CRYPTLIB="${CRYPTLIB} -lcipher"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_tls" >&5
-$as_echo "$have_tls" >&6; }
- if test "x$have_tls" = "xyes"; then
-
-$as_echo "#define HAVE_THREAD_TLS 1" >>confdefs.h
-
- fi
+fi
-talloc_include_dir=
+execinfo_lib_dir=
-# Check whether --with-talloc-include-dir was given.
-if test "${with_talloc_include_dir+set}" = set; then :
- withval=$with_talloc_include_dir; case "$withval" in
+# Check whether --with-execinfo-lib-dir was given.
+if test "${with_execinfo_lib_dir+set}" = set; then :
+ withval=$with_execinfo_lib_dir; case "$withval" in
no)
- as_fn_error $? "Need talloc-include-dir" "$LINENO" 5
- ;;
+ as_fn_error $? "Need execinfo-lib-dir" "$LINENO" 5
+ ;;
yes)
- ;;
+ ;;
*)
- talloc_include_dir="$withval"
- ;;
+ execinfo_lib_dir="$withval"
+ ;;
esac
-fi
-
-
-talloc_lib_dir=
-# Check whether --with-talloc-lib-dir was given.
-if test "${with_talloc_lib_dir+set}" = set; then :
- withval=$with_talloc_lib_dir; case "$withval" in
- no)
- as_fn_error $? "Need talloc-lib-dir" "$LINENO" 5
- ;;
- yes)
- ;;
- *)
- talloc_lib_dir="$withval"
- ;;
- esac
fi
-pcap_include_dir=
+execinfo_include_dir=
-# Check whether --with-pcap-include-dir was given.
-if test "${with_pcap_include_dir+set}" = set; then :
- withval=$with_pcap_include_dir; case "$withval" in
+# Check whether --with-execinfo-include-dir was given.
+if test "${with_execinfo_include_dir+set}" = set; then :
+ withval=$with_execinfo_include_dir; case "$withval" in
no)
- as_fn_error $? "Need pcap-include-dir" "$LINENO" 5
- ;;
+ as_fn_error $? "Need execinfo-include-dir" "$LINENO" 5
+ ;;
yes)
- ;;
+ ;;
*)
- pcap_include_dir="$withval"
- ;;
+ execinfo_include_dir="$withval"
+ ;;
esac
-fi
-
-
-pcap_lib_dir=
-# Check whether --with-pcap-lib-dir was given.
-if test "${with_pcap_lib_dir+set}" = set; then :
- withval=$with_pcap_lib_dir; case "$withval" in
- no)
- as_fn_error $? "Need pcap-lib-dir" "$LINENO" 5
- ;;
- yes)
- ;;
- *)
- pcap_lib_dir="$withval"
- ;;
- esac
fi
-smart_try_dir="$talloc_include_dir"
+smart_try_dir=$execinfo_include_dir
-ac_safe=`echo "talloc.h" | sed 'y%./+-%__pm%'`
-old_CFLAGS="$CFLAGS"
+ac_safe=`echo "execinfo.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
smart_include=
smart_include_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 talloc.h in $try" >&5
-$as_echo_n "checking for talloc.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for execinfo.h in $try" >&5
+$as_echo_n "checking for execinfo.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
- #include <talloc.h>
+ #include <execinfo.h>
int
main ()
{
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_include" = "x"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for talloc.h" >&5
-$as_echo_n "checking for talloc.h... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for execinfo.h" >&5
+$as_echo_n "checking for execinfo.h... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
- #include <talloc.h>
+ #include <execinfo.h>
int
main ()
{
if test "x$LOCATE" != "x"; then
DIRS=
- file=talloc.h
+ file=execinfo.h
for x in `${LOCATE} $file 2>/dev/null`; do
base=`echo $x | sed "s%/${file}%%"`
eval "smart_include_dir=\"\$smart_include_dir $DIRS\""
for try in $smart_include_dir /usr/local/include /opt/include; do
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for talloc.h in $try" >&5
-$as_echo_n "checking for talloc.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for execinfo.h in $try" >&5
+$as_echo_n "checking for execinfo.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
- #include <talloc.h>
+ #include <execinfo.h>
int
main ()
{
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_include" != "x"; then
eval "ac_cv_header_$ac_safe=yes"
- CFLAGS="$old_CFLAGS $smart_include"
- SMART_CFLAGS="$SMART_CFLAGS $smart_include"
-fi
-
-if test "x$ac_cv_header_talloc_h" != "xyes"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: talloc headers not found. Use --with-talloc-include-dir=<path>." >&5
-$as_echo "$as_me: WARNING: talloc headers not found. Use --with-talloc-include-dir=<path>." >&2;}
- as_fn_error $? "FreeRADIUS requires libtalloc" "$LINENO" 5
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
fi
-smart_try_dir="$talloc_lib_dir"
+if test "x$ac_cv_header_execinfo_h" = "xyes"; then
+ smart_try_dir=$execinfo_lib_dir
-sm_lib_safe=`echo "talloc" | sed 'y%./+-%__p_%'`
-sm_func_safe=`echo "_talloc" | sed 'y%./+-%__p_%'`
+sm_lib_safe=`echo "execinfo" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "backtrace_symbols" | 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 _talloc in -ltalloc in $try" >&5
-$as_echo_n "checking for _talloc in -ltalloc in $try... " >&6; }
- LIBS="-L$try -ltalloc $old_LIBS -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for backtrace_symbols in -lexecinfo in $try" >&5
+$as_echo_n "checking for backtrace_symbols in -lexecinfo in $try... " >&6; }
+ LIBS="-lexecinfo $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-extern char _talloc();
+extern char backtrace_symbols();
int
main ()
{
-_talloc()
+backtrace_symbols()
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-L$try -ltalloc -Wl,-rpath,$try"
+ smart_lib="-lexecinfo"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
break
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 _talloc in -ltalloc" >&5
-$as_echo_n "checking for _talloc in -ltalloc... " >&6; }
- LIBS="-ltalloc $old_LIBS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for backtrace_symbols in -lexecinfo" >&5
+$as_echo_n "checking for backtrace_symbols in -lexecinfo... " >&6; }
+ LIBS="-lexecinfo $old_LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-extern char _talloc();
+extern char backtrace_symbols();
int
main ()
{
-_talloc()
+backtrace_symbols()
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-ltalloc"
+ smart_lib="-lexecinfo"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
if test "x$LOCATE" != "x"; then
DIRS=
- file=libtalloc${libltdl_cv_shlibext}
+ file=libexecinfo${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
base=`echo $x | sed "s%/${file}%%"`
if test "x$LOCATE" != "x"; then
DIRS=
- file=libtalloc.a
+ file=libexecinfo.a
for x in `${LOCATE} $file 2>/dev/null`; do
base=`echo $x | sed "s%/${file}%%"`
for try in $smart_lib_dir /usr/local/lib /opt/lib; do
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _talloc in -ltalloc in $try" >&5
-$as_echo_n "checking for _talloc in -ltalloc in $try... " >&6; }
- LIBS="-L$try -ltalloc $old_LIBS -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for backtrace_symbols in -lexecinfo in $try" >&5
+$as_echo_n "checking for backtrace_symbols in -lexecinfo in $try... " >&6; }
+ LIBS="-lexecinfo $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-extern char _talloc();
+extern char backtrace_symbols();
int
main ()
{
-_talloc()
+backtrace_symbols()
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-L$try -ltalloc -Wl,-rpath,$try"
+ smart_lib="-lexecinfo"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
break
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_lib $old_LIBS"
- SMART_LIBS="$smart_lib $SMART_LIBS"
-fi
-
-if test "x$ac_cv_lib_talloc__talloc" != "xyes"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: talloc library not found. Use --with-talloc-lib-dir=<path>." >&5
-$as_echo "$as_me: WARNING: talloc library not found. Use --with-talloc-lib-dir=<path>." >&2;}
- as_fn_error $? "FreeRADIUS requires libtalloc" "$LINENO" 5
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for crypt in -lcrypt" >&5
-$as_echo_n "checking for crypt in -lcrypt... " >&6; }
-if ${ac_cv_lib_crypt_crypt+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lcrypt $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ if test "x$ac_cv_lib_execinfo_backtrace_symbols" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if execinfo provided as part of libc" >&5
+$as_echo_n "checking if execinfo provided as part of libc... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char crypt ();
+ #include <execinfo.h>
+
int
main ()
{
-return crypt ();
+
+ void *sym[1];
+ backtrace_symbols(&sym, sizeof(sym))
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_crypt_crypt=yes
-else
- ac_cv_lib_crypt_crypt=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypt_crypt" >&5
-$as_echo "$ac_cv_lib_crypt_crypt" >&6; }
-if test "x$ac_cv_lib_crypt_crypt" = xyes; then :
- CRYPTLIB="-lcrypt"
-
-fi
-
-if test "$CRYPTLIB" != ""; then
-
-$as_echo "#define HAVE_CRYPT /**/" >>confdefs.h
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ ac_cv_lib_execinfo_backtrace_symbols="yes"
else
- ac_fn_c_check_func "$LINENO" "crypt" "ac_cv_func_crypt"
-if test "x$ac_cv_func_crypt" = xyes; then :
-
-$as_echo "#define HAVE_CRYPT /**/" >>confdefs.h
-
-fi
-fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for setkey in -lcipher" >&5
-$as_echo_n "checking for setkey in -lcipher... " >&6; }
-if ${ac_cv_lib_cipher_setkey+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lcipher $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char setkey ();
-int
-main ()
-{
-return setkey ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_cipher_setkey=yes
-else
- ac_cv_lib_cipher_setkey=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cipher_setkey" >&5
-$as_echo "$ac_cv_lib_cipher_setkey" >&6; }
-if test "x$ac_cv_lib_cipher_setkey" = xyes; then :
- CRYPTLIB="${CRYPTLIB} -lcipher"
-
-fi
+ fi
+ if test "x$ac_cv_lib_execinfo_backtrace_symbols" = "xyes"; then
+$as_echo "#define HAVE_EXECINFO 1" >>confdefs.h
+ fi
+fi
pcre_lib_dir=
-# Check whether --with-rlm-pcre-lib-dir was given.
-if test "${with_rlm_pcre_lib_dir+set}" = set; then :
- withval=$with_rlm_pcre_lib_dir; case "$withval" in
+# Check whether --with-pcre-lib-dir was given.
+if test "${with_pcre_lib_dir+set}" = set; then :
+ withval=$with_pcre_lib_dir; case "$withval" in
no)
- as_fn_error $? "Need rlm-pcre-lib-dir" "$LINENO" 5
+ as_fn_error $? "Need pcre-lib-dir" "$LINENO" 5
;;
yes)
;;
pcre_include_dir=
-# Check whether --with-rlm-pcre-include-dir was given.
-if test "${with_rlm_pcre_include_dir+set}" = set; then :
- withval=$with_rlm_pcre_include_dir; case "$withval" in
+# Check whether --with-pcre-include-dir was given.
+if test "${with_pcre_include_dir+set}" = set; then :
+ withval=$with_pcre_include_dir; case "$withval" in
no)
- as_fn_error $? "Need rlm-pcre-include-dir" "$LINENO" 5
+ as_fn_error $? "Need pcre-include-dir" "$LINENO" 5
;;
yes)
;;
ac_safe=`echo "pcreposix.h" | sed 'y%./+-%__pm%'`
-old_CFLAGS="$CFLAGS"
+old_CPPFLAGS="$CPPFLAGS"
smart_include=
smart_include_dir=
for try in $smart_try_dir; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcreposix.h in $try" >&5
$as_echo_n "checking for pcreposix.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_include" = "x"; then
for try in $smart_include_dir /usr/local/include /opt/include; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcreposix.h in $try" >&5
$as_echo_n "checking for pcreposix.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_include" != "x"; then
eval "ac_cv_header_$ac_safe=yes"
- CFLAGS="$old_CFLAGS $smart_include"
- SMART_CFLAGS="$SMART_CFLAGS $smart_include"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
fi
if test "x$ac_cv_header_pcreposix_h" = "xyes"; then
ac_safe=`echo "regex.h" | sed 'y%./+-%__pm%'`
-old_CFLAGS="$CFLAGS"
+old_CPPFLAGS="$CPPFLAGS"
smart_include=
smart_include_dir=
for try in $smart_try_dir; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for regex.h in $try" >&5
$as_echo_n "checking for regex.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_include" = "x"; then
for try in $smart_include_dir /usr/local/include /opt/include; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for regex.h in $try" >&5
$as_echo_n "checking for regex.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_include" != "x"; then
eval "ac_cv_header_$ac_safe=yes"
- CFLAGS="$old_CFLAGS $smart_include"
- SMART_CFLAGS="$SMART_CFLAGS $smart_include"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
fi
if test "x$ac_cv_header_regex_h" = "xyes"; then
unset ac_cv_env_LIBS_set
unset ac_cv_env_LIBS_value
- ac_config_files="$ac_config_files ./Make.inc ./src/include/build-radpaths-h ./src/main/radsniff.mk ./src/main/checkrad ./src/main/radlast ./src/main/radtest ./scripts/rc.radiusd ./scripts/cron/radiusd.cron.daily ./scripts/cron/radiusd.cron.monthly ./scripts/cryptpasswd ./raddb/dictionary ./raddb/radrelay.conf ./raddb/radiusd.conf"
+ ac_config_files="$ac_config_files ./Make.inc ./src/include/build-radpaths-h ./src/main/radsniff.mk ./src/main/checkrad ./src/main/radlast ./src/main/radtest ./scripts/rc.radiusd ./scripts/cron/radiusd.cron.daily ./scripts/cron/radiusd.cron.monthly ./scripts/cryptpasswd ./raddb/radrelay.conf ./raddb/radiusd.conf"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
"./scripts/cron/radiusd.cron.daily") CONFIG_FILES="$CONFIG_FILES ./scripts/cron/radiusd.cron.daily" ;;
"./scripts/cron/radiusd.cron.monthly") CONFIG_FILES="$CONFIG_FILES ./scripts/cron/radiusd.cron.monthly" ;;
"./scripts/cryptpasswd") CONFIG_FILES="$CONFIG_FILES ./scripts/cryptpasswd" ;;
- "./raddb/dictionary") CONFIG_FILES="$CONFIG_FILES ./raddb/dictionary" ;;
"./raddb/radrelay.conf") CONFIG_FILES="$CONFIG_FILES ./raddb/radrelay.conf" ;;
"./raddb/radiusd.conf") CONFIG_FILES="$CONFIG_FILES ./raddb/radiusd.conf" ;;
AC_CANONICAL_SYSTEM
dnl #
-dnl # As of OSX 10.9 (Mavericks), /usr is no longer populated with the
-dnl # standard set of headers and libraries, instead were meant to use
-dnl # one of the SDKs which contains system headers and libraries for
-dnl # different versions of OSX and iOS.
-dnl #
-case "$host" in
- *-darwin*)
- dnl #
- dnl # The version of GCC apple ships with Mavericks works out of the
- dnl # box, and presumably selects the highest version SDK for OSX.
- dnl #
- AC_MSG_CHECKING([if cc is apple llvm])
- if ! $CC --version 2>&1 | grep -I 'Apple LLVM' > /dev/null; then
- AC_MSG_RESULT(no)
- AC_CHECK_PROG(SW_VERS, sw_vers, yes, no)
- AC_CHECK_PROG(XCODEBUILD, xcodebuild, yes, no)
-
- if test "x$SW_VERS" = "xyes" && test "x$XCODEBUILD" = "xyes"; then
- AC_MSG_NOTICE([determining OSX SDK path])
- osx_sdk_path=$(xcodebuild -version -sdk macosx$(sw_vers -productVersion | egrep -o '^[[0-9]]+\.[[0-9]]+') Path)
- AC_MSG_RESULT([$osx_sdk_path])
-
- dnl #
- dnl # We need to export these, else the child configure scripts all fail
- dnl # their compiler checks.
- dnl #
- export CFLAGS="$CFLAGS --sysroot=$osx_sdk_path"
- export CPPFLAGS="$CPPFLAGS --sysroot=$osx_sdk_path"
- export LDFLAGS="$LDFLAGS -L$osx_sdk_path/usr/lib/"
- DARWIN_CFLAGS="--sysroot=$osx_sdk_path"
- AC_SUBST(DARWIN_CFLAGS)
- fi
- else
- AC_MSG_RESULT(yes)
- fi
- ;;
-esac
-
-dnl #
dnl # Check for GNU cc
dnl #
AC_PROG_CC
dnl # check for system bytesex
dnl # AC_DEFINES WORDS_BIGENDIAN
dnl #
-AC_C_BIGENDIAN
+AC_C_BIGENDIAN(
+ [AC_DEFINE(BIG_ENDIAN, 1, [Define if your processor stores words with the most significant byte first])],
+ [AC_DEFINE(LITTLE_ENDIAN, 1, [Define if your processor stores words with the least significant byte first])]
+)
dnl #
dnl # Find GNU Make.
AC_SUBST(raddbdir)
AC_MSG_RESULT($raddbdir)
+dnl #
+dnl # extra argument: --with-dictdir
+dnl #
+dictdir='${datarootdir}/freeradius'
+AC_MSG_CHECKING(dictdir)
+AC_ARG_WITH(dictdir,
+[ --with-dictdir=DIR directory for dictionary files [DATAROOTDIR/freeradius] ],
+[ case "$withval" in
+ no)
+ AC_MSG_ERROR([Need dictdir])
+ ;;
+ yes)
+ ;;
+ [[\\/$]]* | ?:[[\\/]]* )
+ dictdir="$withval"
+ ;;
+ *)
+ AC_MSG_ERROR([expected an absolute directory name for --with-dictdir: $withval])
+ ;;
+ esac ]
+)
+AC_SUBST(dictdir)
+AC_MSG_RESULT($dictdir)
+
modconfdir='${raddbdir}/mods-config'
AC_SUBST(modconfdir)
USE_SHARED_LIBS=yes
AC_ARG_WITH(shared-libs,
-[ --with-shared-libs build dynamic libraries and link against them. (default=yes)],
+[AS_HELP_STRING([--with-shared-libs ],
+[build dynamic libraries and link against them. (default=yes)])],
[ case "$withval" in
no)
USE_SHARED_LIBS=no
dnl #
EXPERIMENTAL=
AC_ARG_WITH(experimental-modules,
-[ --with-experimental-modules use experimental and unstable modules. (default=no, unless --enable-developer=yes) ],
+[AS_HELP_STRING([--with-experimental-modules],
+[use experimental and unstable modules. (default=no, unless --enable-developer=yes)])],
[ case "$withval" in
yes)
EXPERIMENTAL=yes
dnl #
WITH_UDPFROMTO=yes
AC_ARG_WITH(udpfromto,
-[ --with-udpfromto compile in UDPFROMTO support. (default=yes)],
+[ --with-udpfromto compile in UDPFROMTO support. (default=yes)],
[ case "$withval" in
yes)
WITH_UDPFROMTO=yes
fi
dnl #
-dnl # extra argument: --with-openssl
+dnl # These next two arguments don't actually do anything. They're
+dnl # place holders so that the top-level configure script can tell
+dnl # the user how to configure lower-level modules
dnl #
-WITH_OPENSSL=yes
-AC_ARG_WITH(openssl,
-[ --with-openssl use OpenSSL. (default=yes)],
+
+dnl #
+dnl # extra argument: --with-rlm-FOO-lib-dir
+dnl #
+AC_ARG_WITH(rlm-FOO-lib-dir,
+[AS_HELP_STRING([--with-rlm-FOO-lib-dir=DIR],
+[directory in which to look for library files used by module FOO])],
[ case "$withval" in
- no)
- WITH_OPENSSL=no
- ;;
*)
- WITH_OPENSSL=yes
;;
esac ]
)
dnl #
-dnl # extra argument: --with-openssl-includes=dir
+dnl # extra argument: --with-rlm-FOO-include-dir
dnl #
-OPENSSL_INCLUDE_DIR=
-AC_ARG_WITH(openssl-includes,
-[ --with-openssl-includes=DIR directory to look for OpenSSL include files in],
+AC_ARG_WITH(rlm-FOO-include-dir,
+[AS_HELP_STRING([--with-rlm-FOO-include-dir=DIR],
+[directory in which to look for include files used by module FOO])],
[ case "$withval" in
- *) OPENSSL_INCLUDE_DIR="$withval"
+ *)
;;
esac ]
)
dnl #
-dnl # extra argument: --with-openssl-libraries=dir
+dnl # extra argument: --with-openssl
dnl #
-OPENSSL_LIB_DIR=
-AC_ARG_WITH(openssl-libraries,
-[ --with-openssl-libraries=DIR directory to look for OpenSSL library files in],
+WITH_OPENSSL=yes
+AC_ARG_WITH(openssl,
+[ --with-openssl use OpenSSL. (default=yes)],
[ case "$withval" in
- *) OPENSSL_LIB_DIR="$withval"
+ no)
+ WITH_OPENSSL=no
+ ;;
+ *)
+ WITH_OPENSSL=yes
;;
esac ]
)
dnl #
-dnl # These next two arguments don't actually do anything. They're
-dnl # place holders so that the top-level configure script can tell
-dnl # the user how to configure lower-level modules
+dnl # extra argument: --with-openssl-lib-dir=dir
dnl #
-
-dnl #
-dnl # extra argument: --with-rlm-FOO-lib-dir
-dnl #
-AC_ARG_WITH(rlm-FOO-lib-dir,
-[ --with-rlm-FOO-lib-dir=DIR directory to look for library files used by module FOO in],
+openssl_lib_dir=
+AC_ARG_WITH(openssl-lib-dir,
+[AS_HELP_STRING([--with-openssl-lib-dir=DIR],
+[directory to look for OpenSSL library files])],
[ case "$withval" in
- *)
+ *) openssl_lib_dir="$withval"
;;
esac ]
)
dnl #
-dnl # extra argument: --with-rlm-FOO-include-dir
+dnl # extra argument: --with-openssl-includes=dir
dnl #
-AC_ARG_WITH(rlm-FOO-include-dir,
-[ --with-rlm-FOO-include-dir=DIR directory to look for include files used by module FOO in],
+openssl_include_dir=
+AC_ARG_WITH(openssl-include-dir,
+[AS_HELP_STRING([--with-openssl-include-dir=DIR],
+[directory to look for OpenSSL include files])],
[ case "$withval" in
- *)
+ *) openssl_include_dir="$withval"
;;
esac ]
)
dnl #
dnl #############################################################
+dnl Check for talloc
+dnl extra argument: --with-talloc-lib-dir=DIR
+talloc_lib_dir=
+AC_ARG_WITH(talloc-lib-dir,
+ [AS_HELP_STRING([--with-talloc-lib-dir=DIR],
+ [directory in which to look for talloc library files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR([Need talloc-lib-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ talloc_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-talloc-include-dir=DIR
+talloc_include_dir=
+AC_ARG_WITH(talloc-include-dir,
+ [AS_HELP_STRING([--with-talloc-include-dir=DIR],
+ [directory in which to look for talloc include files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR([Need talloc-include-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ talloc_include_dir="$withval"
+ ;;
+ esac])
+
+smart_try_dir="$talloc_lib_dir"
+FR_SMART_CHECK_LIB(talloc, _talloc)
+if test "x$ac_cv_lib_talloc__talloc" != "xyes"; then
+ AC_MSG_WARN([talloc library not found. Use --with-talloc-lib-dir=<path>.])
+ AC_MSG_ERROR([FreeRADIUS requires libtalloc])
+fi
+
+TALLOC_LIBS="${smart_lib}"
+TALLOC_LDFLAGS="${smart_ldflags}"
+AC_SUBST(TALLOC_LIBS)
+AC_SUBST(TALLOC_LDFLAGS)
+LIBS="$old_LIBS"
+
dnl #
dnl # If using pthreads, check for -lpthread (posix) or -lc_r (*BSD)
dnl #
CFLAGS="$CFLAGS -mt"
fi
- AC_CHECK_HEADERS(pthread.h, [], [ WITH_THREADS="no" ])
+ AC_CHECK_HEADERS(pthread.h, [],
+ [
+ WITH_THREADS="no"
+ fail=[pthread.h]
+ ])
dnl #
dnl # pthread stuff is usually in -lpthread
LIBS="-lpthread $LIBS"
],
[
+ dnl #
+ dnl # -pthread is not a typo, it's a GCC option which sets additional flags required
+ dnl # for multithreading with the pthreads library.
+ dnl #
AC_CHECK_LIB(c_r, pthread_create,
[ CFLAGS="$CFLAGS -pthread -D_THREAD_SAFE" ],
- [ WITH_THREADS="no" ]
+ [
+ WITH_THREADS="no"
+ fail=[-lpthread]
+ ]
)
]
)
+
+ if test "x$WITH_THREADS" != "xyes"; then
+ AC_MSG_WARN([silently not building with thread support.])
+ AC_MSG_WARN([FAILURE: thread support requires: $fail.])
+ else
+ AC_DEFINE(WITH_THREADS, [1], [define if you want thread support])
+ fi
fi
dnl #
)
fi
-if test "x$WITH_THREADS" = "xyes"; then
- AC_DEFINE(WITH_THREADS, [1], [define if you want thread support])
-fi
-
dnl #
dnl # Check if we need -lsocket
dnl #
dnl #
dnl # Check the pcap library for the RADIUS sniffer.
dnl #
+dnl extra argument: --with-pcap-lib-dir=DIR
+pcap_lib_dir=
+AC_ARG_WITH(pcap-lib-dir,
+ [AS_HELP_STRING([--with-pcap-lib-dir=DIR],
+ [directory in which to look for pcap library files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR([Need pcap-lib-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ pcap_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-pcap-include-dir=DIR
+pcap_include_dir=
+AC_ARG_WITH(pcap-include-dir,
+ [AS_HELP_STRING([--with-pcap-include-dir=DIR],
+ [directory in which to look for pcap include files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR([Need pcap-include-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ pcap_include_dir="$withval"
+ ;;
+ esac])
+
smart_try_dir="$pcap_lib_dir"
FR_SMART_CHECK_LIB(pcap, pcap_open_live)
if test "x$ac_cv_lib_pcap_pcap_open_live" != "xyes"; then
- AC_MSG_WARN([pcap library not found. Use --with-pcap-lib-dir=<path>.])
- AC_MSG_WARN([pcap library not found, silently disabling the RADIUS sniffer and ARP listener.])
+ AC_MSG_WARN([pcap library not found, silently disabling the RADIUS sniffer, and ARP listener. Use --with-pcap-lib-dir=<path>.])
else
- PCAP_LIBS="${smart_lib}"
- LIBS=$old_LIBS
AC_DEFINE(HAVE_LIBPCAP, 1,
[Define to 1 if you have the `pcap' library (-lpcap).]
)
+
+ AC_CHECK_FUNCS(\
+ pcap_fopen_offline \
+ pcap_dump_fopen \
+ pcap_create \
+ pcap_activate
+ )
+
+ PCAP_LIBS="${smart_lib}"
+ PCAP_LDFLAGS="${smart_ldflags}"
+fi
+dnl Set by FR_SMART_CHECK_LIB
+LIBS="${old_LIBS}"
+
+dnl Check for collectdclient
+dnl extra argument: --with-collectdclient-lib-dir=DIR
+collectdclient_lib_dir=
+AC_ARG_WITH(collectdclient-lib-dir,
+ [AS_HELP_STRING([--with-collectdclient-lib-dir=DIR],
+ [directory in which to look for collectdclient library files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR([Need collectdclient-lib-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ collectdclient_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-collectdclient-include-dir=DIR
+collectdclient_include_dir=
+AC_ARG_WITH(collectdclient-include-dir,
+ [AS_HELP_STRING([--with-collectdclient-include-dir=DIR],
+ [directory in which to look for collectdclient include files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR([Need collectdclient-include-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ collectdclient_include_dir="$withval"
+ ;;
+ esac])
+
+smart_try_dir="$collectdclient_lib_dir"
+FR_SMART_CHECK_LIB(collectdclient, lcc_connect)
+if test "x$ac_cv_lib_collectdclient_lcc_connect" != "xyes"; then
+ AC_MSG_WARN([collectdclient library not found. Use --with-collectdclient-lib-dir=<path>.])
+else
+ COLLECTDC_LIBS="${smart_lib}"
+ COLLECTDC_LDFLAGS="${smart_ldflags}"
fi
+dnl Set by FR_SMART_CHECKLIB
+LIBS="${old_LIBS}"
VL_LIB_READLINE
dnl #############################################################
dnl #
+dnl # Check for talloc header files
+dnl #
+smart_try_dir="$talloc_include_dir"
+FR_SMART_CHECK_INCLUDE([talloc.h])
+if test "x$ac_cv_header_talloc_h" != "xyes"; then
+ AC_MSG_WARN([talloc headers not found. Use --with-talloc-include-dir=<path>.])
+ AC_MSG_ERROR([FreeRADIUS requires libtalloc])
+fi
+
+dnl #
dnl # Interix requires us to set -D_ALL_SOURCE, otherwise
dnl # getopt will be #included, but won't link. <sigh>
dnl #
-dnl #
case "$host" in
*-interix*)
CFLAGS="$CFLAGS -D_ALL_SOURCE"
stddef.h \
fnmatch.h \
sia.h \
- siad.h
+ siad.h \
+ features.h \
+ limits.h
)
dnl #
dnl # FreeBSD requires sys/socket.h before net/if.h
dnl #
AC_CHECK_HEADERS(net/if.h, [], [],
-[
- #ifdef HAVE_SYS_SOCKET_H
- # include <sys/socket.h>
- #endif
-])
+ [
+ #ifdef HAVE_SYS_SOCKET_H
+ # include <sys/socket.h>
+ #endif
+ ]
+)
dnl #
dnl # other checks which require headers
dnl # Were we told to use OpenSSL, if we were and we find an error, call AC_MSG_FAILURE and exit
dnl #
if test "x$WITH_OPENSSL" = xyes; then
- old_LIBS=$LIBS
- old_LDFLAGS="$LDFLAGS"
-
- OPENSSL_INCLUDE="-DNO_OPENSSL"
- OPENSSL_LIBS=
- if test "x$OPENSSL_LIB_DIR" != "x"; then
- LDFLAGS="-L$OPENSSL_LIB_DIR $LDFLAGS"
- fi
+ OLD_LIBS="$LIBS"
dnl #
- dnl # Check we can link to libssl
+ dnl # Apparently OpenSSL will attempt to build with kerberos if we don't pass this?!
dnl #
- AC_CHECK_LIB(crypto, DH_new,
- [
- LIBS="-lcrypto $LIBS"
- AC_DEFINE(HAVE_LIBCRYPTO, 1, [Define to 1 if you have the `crypto' library (-lcrypto).])
- AC_CHECK_LIB(ssl, SSL_new,
- [
- AC_DEFINE(HAVE_LIBSSL, 1, [Define to 1 if you have the `ssl' library (-lssl).])
- if test "x$OPENSSL_LIB_DIR" != "x"; then
- OPENSSL_LIBS="-L$OPENSSL_LIB_DIR"
- fi
- OPENSSL_LIBS="$OPENSSL_LIBS -lcrypto -lssl -lcrypto"
- ],
- [
- AC_MSG_FAILURE([failed linking to libssl])
- ]
- )
- ],
- []
- )
+ CFLAGS="$CFLAGS -DOPENSSL_NO_KRB5"
dnl #
- dnl # Check we can find required headers
+ dnl # Check we can link to libcrypto and libssl
dnl #
- old_CPPFLAGS=$CPPFLAGS
- old_CFLAGS=$CFLAGS
- if test "x$OPENSSL_INCLUDE_DIR" != "x"; then
- CPPFLAGS="-isystem $OPENSSL_INCLUDE_DIR $CPPFLAGS"
- CFLAGS="-isystem $OPENSSL_INCLUDE_DIR $CFLAGS"
+ smart_try_dir="$openssl_lib_dir"
+ FR_SMART_CHECK_LIB(crypto, DH_new)
+ if test "x$ac_cv_lib_crypto_DH_new" = "xyes"; then
+ AC_DEFINE(HAVE_LIBCRYPTO, 1, [Define to 1 if you have the `crypto' library (-lcrypto).])
+ OPENSSL_LIBS="$smart_lib"
+ OPENSSL_LDFLAGS="$smart_ldflags"
+
+ FR_SMART_CHECK_LIB(ssl, SSL_new)
+ if test "x$ac_cv_lib_ssl_SSL_new" != "xyes"; then
+ AC_MSG_FAILURE([failed linking to libssl. Use --with-openssl-lib-dir=<path>, or --with-openssl=no (builds without OpenSSL)])
+ else
+ AC_DEFINE(HAVE_LIBSSL, 1, [Define to 1 if you have the `ssl' library (-lssl).])
+ OPENSSL_LIBS="$OPENSSL_LIBS $smart_lib"
+
+ if test "$OPENSSL_LDFLAGS" != "$smart_ldflags"; then
+ AC_MSG_FAILURE(["inconsistent LDFLAGS between -lssl '$smart_ldflags' and -lcrypto '$OPENSSL_LDFLAGS'"])
+ fi
+ fi
+ else
+ AC_MSG_FAILURE([failed linking to libcrypto. Use --with-openssl-lib-dir=<path>, or --with-openssl=no (builds without OpenSSL)])
fi
- dnl #
- dnl # Stupid RedHat shit
- dnl #
- CPPFLAGS="$CPPFLAGS -DOPENSSL_NO_KRB5"
- AC_CHECK_HEADERS( \
- openssl/ssl.h \
- openssl/crypto.h \
- openssl/err.h \
- openssl/evp.h \
- openssl/md5.h \
- openssl/md4.h \
- openssl/sha.h \
- openssl/ocsp.h \
- openssl/engine.h,
- [],
- [
- AC_MSG_FAILURE([failed locating OpenSSL headers])
- ]
- )
+ smart_try_dir="$openssl_include_dir"
+ FR_SMART_CHECK_INCLUDE(openssl/ssl.h)
+ if test "x$ac_cv_header_openssl_ssl_h" = "xyes"; then
+ AC_DEFINE(HAVE_OPENSSL_SSL_H, 1, [Define to 1 if you have the <openssl/ssl.h> header file.])
+
+ AC_CHECK_HEADERS( \
+ openssl/crypto.h \
+ openssl/err.h \
+ openssl/evp.h \
+ openssl/md5.h \
+ openssl/md4.h \
+ openssl/sha.h \
+ openssl/ocsp.h \
+ openssl/engine.h,
+ [],
+ [
+ AC_MSG_FAILURE([failed locating OpenSSL headers. Use --with-openssl-include-dir=<path>, or --with-openssl=no (builds without OpenSSL)])
+ ]
+ )
- AC_MSG_CHECKING([for OpenSSL version >= 0.9.7])
- AC_EGREP_CPP(yes,
- [#include <openssl/crypto.h>
- #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
- yes
- #endif
- ],
- [
- AC_MSG_RESULT(yes)
- ],
- [
- AC_MSG_RESULT(no)
- AC_MSG_FAILURE([OpenSSL version too old])
- ]
- )
+ AC_MSG_CHECKING([for OpenSSL version >= 0.9.7])
+ AC_EGREP_CPP(yes,
+ [#include <openssl/crypto.h>
+ #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
+ yes
+ #endif
+ ],
+ [
+ AC_MSG_RESULT(yes)
+ ],
+ [
+ AC_MSG_RESULT(no)
+ AC_MSG_FAILURE([OpenSSL version too old])
+ ]
+ )
- if test "x$OPENSSL_INCLUDE_DIR" != "x"; then
- OPENSSL_INCLUDE="-isystem $OPENSSL_INCLUDE_DIR -DOPENSSL_NO_KRB5"
- else
- OPENSSL_INCLUDE="-DOPENSSL_NO_KRB5"
- fi
+ dnl #
+ dnl # CPPFLAGS are passed to the compiler first, so we use
+ dnl # them to ensure things like --sysroot don't override the
+ dnl # library location we discovered previously.
+ dnl #
+ old_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$OPENSSL_LDFLAGS $CPPFLAGS"
- dnl #
- dnl # Now check that the header versions match the library
- dnl #
- AC_MSG_CHECKING([OpenSSL library and header version consistency])
- AC_RUN_IFELSE(
- [AC_LANG_PROGRAM(
- [[
- #include <stdio.h>
- #include <openssl/opensslv.h>
- #include <openssl/crypto.h>
- ]],
- [[
- if (SSLeay() == OPENSSL_VERSION_NUMBER) {
- return 0;
- } else {
+ dnl #
+ dnl # Now check that the header versions match the library
+ dnl #
+ AC_MSG_CHECKING([OpenSSL library and header version consistency])
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[
+ #include <stdio.h>
+ #include <openssl/opensslv.h>
+ #include <openssl/crypto.h>
+ ]],
+ [[
printf("library: %lx header: %lx... ", (unsigned long) SSLeay(), (unsigned long) OPENSSL_VERSION_NUMBER);
- return 1;
- }
- ]]
- )],
- [
- AC_MSG_RESULT(yes)
- ],
- [
- AC_MSG_RESULT(no)
- AC_MSG_FAILURE([OpenSSL library version does not match header version])
- ]
- )
-
- if test "x$OPENSSL_LIBS" = x; then
- LIBS=$old_LIBS
- LDFLAGS="$old_LDFLAGS"
- fi
- if test "x$OPENSSL_INCLUDE" = x; then
- CPPFLAGS=$old_CPPFLAGS
- CFLAGS=$old_CFLAGS
+ if (SSLeay() == OPENSSL_VERSION_NUMBER) {
+ return 0;
+ } else {
+ return 1;
+ }
+ ]]
+ )],
+ [
+ AC_MSG_RESULT(yes)
+ ],
+ [
+ AC_MSG_RESULT(no)
+ AC_MSG_FAILURE([OpenSSL library version does not match header version])
+ ]
+ )
+ CPPFLAGS="$old_CPPFLAGS"
fi
-fi
-AC_SUBST(OPENSSL_INCLUDE)
-AC_SUBST(OPENSSL_LIBS)
-export OPENSSL_LIBS
+ LIBS="$OLD_LIBS"
+ AC_SUBST(OPENSSL_LIBS)
+ AC_SUBST(OPENSSL_LDFLAGS)
+ export OPENSSL_LIBS OPENSSL_LDFLAGS
+fi
dnl #
dnl # Check the pcap includes for the RADIUS sniffer.
if test "x$PCAP_LIBS" = x; then
AC_MSG_NOTICE([skipping test for pcap.h.])
else
+ dnl #
+ dnl # Check for pcap header files
+ dnl #
smart_try_dir="$pcap_include_dir"
FR_SMART_CHECK_INCLUDE([pcap.h])
- if test "x$ac_cv_header_pcap_h" != "xyes"; then
- AC_MSG_WARN([pcap headers not found. Use --with-pcap-include-dir=<path>.])
- AC_MSG_WARN([pcap.h not found, silently disabling the RADIUS sniffer, and ARP listener.])
- else
+ if test "x$ac_cv_header_pcap_h" == "xyes"; then
AC_DEFINE(HAVE_PCAP_H, 1, [Define to 1 if you have the <pcap.h> header file.])
+ AC_SUBST(PCAP_LIBS)
+ AC_SUBST(PCAP_LDFLAGS)
+ else
+ AC_MSG_WARN([pcap headers not found, silently disabling the RADIUS sniffer, and ARP listener. Use --with-pcap-include-dir=<path>.])
+ fi
+fi
- AC_CHECK_LIB(pcap, pcap_fopen_offline,
- [
- AC_DEFINE(HAVE_PCAP_FOPEN_OFFLINE, 1, [Define to 1 if you have the function pcap_fopen_offline.])
- ]
- )
-
- AC_CHECK_LIB(pcap, pcap_dump_fopen,
- [
- AC_DEFINE(HAVE_PCAP_DUMP_FOPEN, 1, [Define to 1 if you have the function pcap_dump_fopen.])
- ]
- )
+dnl Check for collectd-client
+if test "x$COLLECTDC_LIBS" = x; then
+ AC_MSG_NOTICE([skipping test for collectd/client.h.])
+else
+ dnl #
+ dnl # Check for collectd-client header files
+ dnl #
+ smart_try_dir="$collectdclient_include_dir"
+ FR_SMART_CHECK_INCLUDE([collectd/client.h])
+ if test "x$ac_cv_header_collectd_client_h" == "xyes"; then
+ AC_DEFINE(HAVE_COLLECTDC_H, 1, [Define to 1 if you have the `collectdclient' library (-lcollectdclient).])
+ AC_SUBST(COLLECTDC_LIBS)
+ AC_SUBST(COLLECTDC_LDFLAGS)
+ else
+ AC_MSG_WARN([collectdclient headers not found. Use --with-collectdclient-include-dir=<path>.])
fi
fi
-AC_SUBST(PCAP_LIBS)
dnl #############################################################
dnl #
uint32_t, unsigned int, [uint32_t should be the canonical 'network integer']
)
+dnl #
+dnl # Check for uint64_t
+dnl #
+FR_CHECK_TYPE_INCLUDE(
+ [
+ #ifdef HAVE_INTTYPES_H
+ # include <inttypes.h>
+ #endif
+
+ #ifdef HAVE_STDINT_H
+ # include <stdint.h>
+ #endif
+ ],
+ uint64_t, unsigned long long, [uint64_t is required for larger counters]
+)
+
+FR_CHECK_TYPE_INCLUDE(
+ [
+ #ifdef HAVE_SIGNAL_H
+ # include <signal.h>
+ #endif
+ ],
+ sig_t, void(*sig_t)(int), [signal action callback function]
+)
+
+dnl #
+dnl # Check for __uint128_t (compiler builtin)
+dnl #
+AC_CHECK_TYPE(__uint128_t, AC_DEFINE(HAVE___UINT128_T, 1, [compiler specific 128 bit unsigned integer]), [], [])
+
+dnl #
+dnl # Check for uint128_t (fictitious future data type)
+dnl #
+AC_CHECK_TYPE(uint128_t, AC_DEFINE(HAVE_UINT128_T, 1, [128 bit unsigned integer]), [],
+ [
+ #ifdef HAVE_INTTYPES_H
+ # include <inttypes.h>
+ #endif
+
+ #ifdef HAVE_STDINT_H
+ # include <stdint.h>
+ #endif
+ ]
+)
+
AC_CHECK_TYPE(struct in6_addr, AC_DEFINE(HAVE_STRUCT_IN6_ADDR, 1, [IPv6 address structure]), [],
[
#ifdef HAVE_NETINET_IN_H
inet_aton \
inet_pton \
inet_ntop \
+ mallopt \
setlinebuf \
setvbuf \
getusershell \
dnl #
if test -d $srcdir/.git -a "x$GIT" = "xyes"; then
RADIUSD_VERSION_COMMIT=`git log --pretty=format:'%h' -n 1`
- AC_DEFINE_UNQUOTED([RADIUSD_VERSION_COMMIT],["${RADIUSD_VERSION_COMMIT}"],[Commit HEAD at time of configuring])
+ AC_DEFINE_UNQUOTED([RADIUSD_VERSION_COMMIT],[${RADIUSD_VERSION_COMMIT}],[Commit HEAD at time of configuring])
fi
+dnl #
+dnl # check for some compiler features
+dnl #
FR_TLS
+FR_HAVE_BUILTIN_CHOOSE_EXPR
+FR_HAVE_BUILTIN_TYPES_COMPATIBLE_P
dnl #############################################################
dnl #
dnl #
dnl #############################################################
-dnl Check for talloc
-dnl extra argument: --with-talloc-include-dir=DIR
-talloc_include_dir=
-AC_ARG_WITH(talloc-include-dir,
- [ --with-talloc-include-dir=DIR directory to look for talloc include files in],
- [case "$withval" in
- no)
- AC_MSG_ERROR([Need talloc-include-dir])
- ;;
- yes)
- ;;
- *)
- talloc_include_dir="$withval"
- ;;
- esac])
-
-dnl Check for talloc
-dnl extra argument: --with-talloc-lib-dir=DIR
-talloc_lib_dir=
-AC_ARG_WITH(talloc-lib-dir,
- [ --with-talloc-lib-dir=DIR directory to look for talloc library files in],
- [case "$withval" in
- no)
- AC_MSG_ERROR([Need talloc-lib-dir])
- ;;
- yes)
- ;;
- *)
- talloc_lib_dir="$withval"
- ;;
- esac])
-
-dnl Check for pcap
-dnl extra argument: --with-pcap-include-dir=DIR
-pcap_include_dir=
-AC_ARG_WITH(pcap-include-dir,
- [ --with-pcap-include-dir=DIR directory to look for pcap include files in],
- [case "$withval" in
- no)
- AC_MSG_ERROR([Need pcap-include-dir])
- ;;
- yes)
- ;;
- *)
- pcap_include_dir="$withval"
- ;;
- esac])
-
-dnl Check for pcap
-dnl extra argument: --with-pcap-lib-dir=DIR
-pcap_lib_dir=
-AC_ARG_WITH(pcap-lib-dir,
- [ --with-pcap-lib-dir=DIR directory to look for pcap library files in],
- [case "$withval" in
- no)
- AC_MSG_ERROR([Need pcap-lib-dir])
- ;;
- yes)
- ;;
- *)
- pcap_lib_dir="$withval"
- ;;
- esac])
-
dnl #
-dnl # Check for talloc header files
+dnl # Check for talloc_set_memlimit
+dnl # This was only included in version 2.0.8
dnl #
-smart_try_dir="$talloc_include_dir"
-FR_SMART_CHECK_INCLUDE([talloc.h])
-if test "x$ac_cv_header_talloc_h" != "xyes"; then
- AC_MSG_WARN([talloc headers not found. Use --with-talloc-include-dir=<path>.])
- AC_MSG_ERROR([FreeRADIUS requires libtalloc])
-fi
-
-smart_try_dir="$talloc_lib_dir"
-FR_SMART_CHECK_LIB(talloc, _talloc)
-if test "x$ac_cv_lib_talloc__talloc" != "xyes"; then
- AC_MSG_WARN([talloc library not found. Use --with-talloc-lib-dir=<path>.])
- AC_MSG_ERROR([FreeRADIUS requires libtalloc])
-fi
+AC_CHECK_LIB(talloc, talloc_set_memlimit,
+ [
+ AC_DEFINE(HAVE_TALLOC_SET_MEMLIMIT, 1, [Define to 1 if you have the function talloc_set_memlimit.])
+ ]
+)
dnl #
dnl # Check for libcrypt
)
AC_SUBST(CRYPTLIB)
+dnl #
+dnl # Check for libexecinfo support, on some systems this is built into libc
+dnl # on others it's a separate library.
+dnl #
+dnl extra argument: --with-execinfo-lib-dir
+execinfo_lib_dir=
+AC_ARG_WITH(execinfo-lib-dir,
+[AS_HELP_STRING([--with-execinfo-lib-dir=DIR],
+[directory in which to look for execinfo library files])],
+[ case "$withval" in
+ no)
+ AC_MSG_ERROR([Need execinfo-lib-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ execinfo_lib_dir="$withval"
+ ;;
+ esac ]
+)
+
+dnl extra argument: --with-execinfo-include-dir
+execinfo_include_dir=
+AC_ARG_WITH(execinfo-include-dir,
+[AS_HELP_STRING([--with-execinfo-include-dir=DIR],
+[directory in which to look for execinfo include files])],
+[ case "$withval" in
+ no)
+ AC_MSG_ERROR([Need execinfo-include-dir])
+ ;;
+ yes)
+ ;;
+ *)
+ execinfo_include_dir="$withval"
+ ;;
+ esac ]
+)
+
+dnl #
+dnl # Look for execinfo.h and symbols
+dnl #
+smart_try_dir=$execinfo_include_dir
+FR_SMART_CHECK_INCLUDE(execinfo.h)
+if test "x$ac_cv_header_execinfo_h" = "xyes"; then
+ smart_try_dir=$execinfo_lib_dir
+ FR_SMART_CHECK_LIB(execinfo, backtrace_symbols)
+ if test "x$ac_cv_lib_execinfo_backtrace_symbols" != "xyes"; then
+ dnl # Might be provided as part of libc
+ AC_MSG_CHECKING([if execinfo provided as part of libc])
+ AC_TRY_LINK(
+ [
+ #include <execinfo.h>
+ ],
+ [
+ void *sym[1];
+ backtrace_symbols(&sym, sizeof(sym)) ],
+ [
+ AC_MSG_RESULT(yes)
+ ac_cv_lib_execinfo_backtrace_symbols="yes"
+ ],
+ [
+ AC_MSG_RESULT(no)
+ ]
+ )
+ fi
+
+ if test "x$ac_cv_lib_execinfo_backtrace_symbols" = "xyes"; then
+ AC_DEFINE(HAVE_EXECINFO, [1], [define this if we have <execinfo.h> and symbols])
+ fi
+fi
dnl #
dnl # Check for regular expression support, if were using PCRE it MUST be included
dnl #
dnl extra argument: --with-pcre-lib-dir
pcre_lib_dir=
-AC_ARG_WITH(rlm-pcre-lib-dir,
-[ --with-pcre-lib-dir=DIR directory to look for PCRE library files in],
+AC_ARG_WITH(pcre-lib-dir,
+[AS_HELP_STRING([--with-pcre-lib-dir=DIR],
+[directory in which to look for pcre library files])],
[ case "$withval" in
no)
- AC_MSG_ERROR(Need rlm-pcre-lib-dir)
+ AC_MSG_ERROR(Need pcre-lib-dir)
;;
yes)
;;
dnl extra argument: --with-pcre-include--dir
pcre_include_dir=
-AC_ARG_WITH(rlm-pcre-include-dir,
-[ --with-pcre-include-dir=DIR directory to look for PCRE include files in],
+AC_ARG_WITH(pcre-include-dir,
+[AS_HELP_STRING([--with-pcre-include-dir=DIR],
+[directory in which to look for pcre include files])],
[ case "$withval" in
no)
- AC_MSG_ERROR(Need rlm-pcre-include-dir)
+ AC_MSG_ERROR(Need pcre-include-dir)
;;
yes)
;;
./scripts/cron/radiusd.cron.daily \
./scripts/cron/radiusd.cron.monthly \
./scripts/cryptpasswd \
- ./raddb/dictionary \
./raddb/radrelay.conf \
./raddb/radiusd.conf
)
freeradius-ldap
freeradius-mysql
freeradius-postgresql
+freeradius-rest
freeradius-utils
freeradius
libfreeradius-dev
+freeradius (3.0.3+git) unstable; urgency=medium
+
+ * New upstream version.
+
+ -- Alan DeKok <aland@freeradius.org> Fri, 21 Mar 2014 08:30:00 -0400
+
+freeradius (3.0.2+git) unstable; urgency=medium
+
+ * New upstream version.
+
+ -- Alan DeKok <aland@freeradius.org> Wed, 15 Jan 2014 21:23:14 -0400
+
freeradius (3.0.1+git) unstable; urgency=medium
* New upstream version.
Source: freeradius
-Build-Depends: debhelper (>= 9),
+Build-Depends: debhelper (>= 7.4),
quilt,
dpkg-dev (>= 1.13.19),
autotools-dev,
- libpam0g-dev,
- libmysqlclient-dev,
- libsqlite3-dev,
+ libcurl4-openssl-dev,
libgdbm-dev,
- libldap2-dev,
- libsasl2-dev,
libiodbc2-dev,
+ libjson0,
+ libjson0-dev,
libkrb5-dev,
- libperl-dev,
+ libldap2-dev,
+ libpam0g-dev,
libpcap-dev,
- python-dev,
- libreadline-dev,
+ libperl-dev,
+ libmysqlclient-dev,
libpq-dev,
+ libreadline-dev,
+ libsasl2-dev,
+ libsqlite3-dev,
libssl-dev,
libtalloc-dev,
- libyubikey-dev
+ libyubikey-dev,
+ python-dev
Section: net
Priority: optional
Maintainer: Josip Rodin <joy-packages@debian.org>
The FreeRADIUS server can use LDAP to authenticate users, and this module
is necessary for that.
+Package: freeradius-rest
+Architecture: any
+Depends: freeradius (= ${binary:Version}), ${shlibs:Depends}
+Description: REST module for FreeRADIUS server
+ The FreeRADIUS server can make calls to remote web APIs, and this module
+ is necessary for that.
+
Package: freeradius-postgresql
Architecture: any
Depends: freeradius (= ${binary:Version}), ${shlibs:Depends}
Copyright:
-Copyright (C) 2000-2013 The FreeRADIUS Server Project
+Copyright (C) 2000-2014 The FreeRADIUS Server Project
Copyright (C) 1997-1999 Cistron Internet Services B.V.
License:
set -e
case "$1" in
- remove)
- ;;
- purge)
- rmdir --ignore-fail-on-non-empty /etc/freeradius
- ;;
- *)
- ;;
+ remove)
+ ;;
+ purge)
+ if dpkg-statoverride --list | grep -qw /etc/freeradius/dictionary$; then
+ dpkg-statoverride --remove /etc/freeradius/dictionary
+ fi
+
+ if dpkg-statoverride --list | grep -qw /etc/freeradius/radiusd.conf$; then
+ dpkg-statoverride --remove /etc/freeradius/radiusd.conf
+ fi
+
+ if dpkg-statoverride --list | grep -qw /etc/freeradius$; then
+ dpkg-statoverride --remove /etc/freeradius
+ fi
+
+ rmdir --ignore-fail-on-non-empty /etc/freeradius
+ ;;
+ *)
+ ;;
esac
#DEBHELPER#
case "$1" in
configure)
- for file in `find /etc/freeradius/mods-config/sql/main/mysql/ -print`
- do
- if ! dpkg-statoverride --list | grep -qw $file$; then
- dpkg-statoverride --add --update root freerad 0640 $file
- fi
- done
-
- for dir in /etc/freeradius/mods-config/sql/main \
- /etc/freeradius/mods-config/sql/main/mysql
- do
- if ! dpkg-statoverride --list | grep -qw $dir$; then
- dpkg-statoverride --add --update root freerad 2751 $dir
- fi
- done
-
if [ -x "`which invoke-rc.d 2>/dev/null`" ]; then
invoke-rc.d freeradius force-reload
else
case "$1" in
configure)
- for file in `find /etc/freeradius/mods-config/sql/main/postgresql/ -print`
- do
- if ! dpkg-statoverride --list | grep -qw $file$; then
- dpkg-statoverride --add --update root freerad 0640 $file
- fi
- done
-
- for dir in /etc/freeradius/mods-config/sql/main \
- /etc/freeradius/mods-config/sql/main/postgresql
- do
- if ! dpkg-statoverride --list | grep -qw $dir$; then
- dpkg-statoverride --add --update root freerad 2751 $dir
- fi
- done
-
if [ -x "`which invoke-rc.d 2>/dev/null`" ]; then
invoke-rc.d freeradius force-reload
else
--- /dev/null
+usr/lib/freeradius/rlm_rest*.so
--- /dev/null
+#! /bin/sh
+
+set -e
+
+case "$1" in
+ configure)
+ if [ -x "`which invoke-rc.d 2>/dev/null`" ]; then
+ invoke-rc.d freeradius force-reload
+ else
+ /etc/init.d/freeradius force-reload
+ fi
+ ;;
+ abort-upgrade)
+ ;;
+ abort-remove)
+ ;;
+ abort-deconfigure)
+ ;;
+esac
+
+#DEBHELPER#
+
. /lib/lsb/init-functions
test_freeradius_config() {
- log_action_begin_msg "Checking $DESCR configuration"
+ log_action_begin_msg "Checking $DESCR configuration"
- out=`$PROGRAM -Cxl stdout $FREERADIUS_OPTIONS`; ret=$?
- out=`echo "${out}" | tail -n 1 | sed 's/^\s*ERROR:\s*\(.*\)\s*$/\1/'`
- log_action_end_msg $ret "$out"
- return $ret
+ out=`$PROGRAM -Cxl stdout $FREERADIUS_OPTIONS`; ret=$?
+ out=`echo "${out}" | tail -n 1 | sed 's/^\s*ERROR:\s*\(.*\)\s*$/\1/'`
+ log_action_end_msg $ret "$out"
+ return $ret
}
if [ -r /etc/default/$PROG ]; then
- . /etc/default/$PROG
+ . /etc/default/$PROG
fi
test -f $PROGRAM || exit 0
# /var/run may be a tmpfs
if [ ! -d /var/run/freeradius ]; then
- mkdir -p /var/run/freeradius
- chown freerad:freerad /var/run/freeradius
+ mkdir -p /var/run/freeradius
+ chown freerad:freerad /var/run/freeradius
fi
export PATH="${PATH:+$PATH:}/usr/sbin:/sbin"
ret=0
case "$1" in
- start)
- log_daemon_msg "Starting $DESCR" "$PROG"
+ start)
+ log_daemon_msg "Starting $DESCR" "$PROG"
- start_daemon -p "$PIDFILE" "$PROGRAM" $FREERADIUS_OPTIONS || ret=$?
- log_end_msg $ret
- ;;
+ # eval allows quoted arguments (config directories for example) to be passed in $FREERADIUS_OPTIONS
+ eval "start_daemon -p '$PIDFILE' '$PROGRAM' $FREERADIUS_OPTIONS" || ret=$?
+ log_end_msg $ret
+ ;;
- stop)
- log_daemon_msg "Stopping $DESCR" "$PROG"
+ stop)
+ log_daemon_msg "Stopping $DESCR" "$PROG"
- killproc -p "$PIDFILE" || ret=$?
- log_end_msg $ret
- ;;
+ killproc -p "$PIDFILE" || ret=$?
+ log_end_msg $ret
+ ;;
- restart|force-reload)
- test_freeradius_config || exit $?
+ restart|force-reload)
+ test_freeradius_config || exit $?
- $0 stop
- $0 start
- ;;
+ $0 stop
+ $0 start
+ ;;
- reload)
- test_freeradius_config || exit $?
+ reload)
+ test_freeradius_config || exit $?
- if status_of_proc -p "$PIDFILE" "$PROG" "$DESCR"; then
- log_daemon_msg "Reloading $DESCR" "$PROG"
+ if status_of_proc -p "$PIDFILE" "$PROG" "$DESCR"; then
+ log_daemon_msg "Reloading $DESCR" "$PROG"
- start-stop-daemon --stop --signal HUP --quiet --pidfile $PIDFILE || ret=$?
- log_end_msg $ret
- fi
- ;;
+ start-stop-daemon --stop --signal HUP --quiet --pidfile $PIDFILE || ret=$?
+ log_end_msg $ret
+ fi
+ ;;
- configtest|testconfig)
- test_freeradius_config || exit $?
- ;;
+ configtest|testconfig)
+ test_freeradius_config || exit $?
+ ;;
- debug)
- $PROGRAM -X $FREERADIUS_OPTIONS
- ;;
+ debug)
+ $PROGRAM -X $FREERADIUS_OPTIONS
+ ;;
- status)
- status_of_proc -p "$PIDFILE" "$PROGRAM" "$PROG" && exit 0 || exit $?
- ;;
+ debug-threaded)
+ $PROGRAM -f -xx -l stdout $FREERADIUS_OPTIONS
+ ;;
- *)
- echo "Usage: $0 start|stop|restart|force-reload|reload|configtest|debug|status"
- exit 1
- ;;
+ status)
+ status_of_proc -p "$PIDFILE" "$PROGRAM" "$PROG" && exit 0 || exit $?
+ ;;
+
+ *)
+ echo "Usage: $0 start|stop|restart|force-reload|reload|configtest|debug|debug-threaded|status"
+ exit 1
+ ;;
esac
exit 0
--- a/Make.inc.in
+++ b/Make.inc.in
-@@ -50,7 +50,7 @@ LDFLAGS = @LDFLAGS@
+@@ -94,7 +94,7 @@
LOGDIR = ${logdir}
RADDBDIR = ${raddbdir}
+RUNDIR = ${localstatedir}/run/freeradius
SBINDIR = ${sbindir}
RADIR = ${radacctdir}
- LIBRADIUS = $(top_builddir)/src/lib/$(LIBPREFIX)freeradius-radius.la
+ LIBRADIUS = $(top_builddir)/src/lib/$(LIBPREFIX)freeradius-radius.la $(TALLOC_LIBS)
--- a/raddb/radiusd.conf.in
+++ b/raddb/radiusd.conf.in
-@@ -62,7 +62,7 @@ radacctdir = @radacctdir@
+@@ -61,7 +61,7 @@
#
# name of the running server. See also the "-n" command-line option.
# Location of config and logfiles.
confdir = ${raddbdir}
-@@ -463,8 +463,8 @@ security {
+@@ -415,8 +415,8 @@
# member. This can allow for some finer-grained access
# controls.
#
if failed host 127.0.0.1 port 1812 type udp protocol radius secret testing123 then alert
if failed host 127.0.0.1 port 1813 type udp protocol radius secret testing123 then alert
if cpu > 95% for 2 cycles then alert
-
+FreeRADIUS 3.0.4 Mon 12 May 2014 15:30:00 EDT urgency=medium
+ Feature improvements
+ * Home server "response_window" can now take fractions of a
+ second. See proxy.conf.
+ * radmin now supports "show module status", as the counterpart
+ to "set module status"
+ * Added dictionary ericsson.packet.ccore.networks
+ * Add %{tag:} expansion to get the tag value of an attribute.
+ * Report 'application_name' in connections to PostgreSQL servers.
+ FreeRADIUS connections will now appear as
+ 'FreeRADIUS <version> - <name>' in pg_stat_activity.
+ * All config item fields are now type checked at compile time
+ to prevent issues similar to #634 occuring again.
+ * Modify pairparsevalue to deal with embedded NULLs better,
+ and use the binary versions of attribute values in rlm_ldap.
+ * "ipaddr" will now use v6 if no v4 address is present. You should
+ use "ipv4addr" or "ipv6addr" to force v4/v6 addresses.
+ * The above applies to "listen", "home_server", and "client" sections.
+ * "client" sections will allow prefixes as "192.192.0/24". The old
+ "netmask" is still accepted, but the new format is preferred.
+
+ Bug fixes
+ * make case-insensitive regular expressions work again.
+ * Added tests for the above
+ * A few more talloc parenting issues
+ * Fix delayed proxy reply handling. Closes #637
+ * Fix OpenSSL initialization order when using
+ RADIUS/TLS. Fixes #646
+ * Don't double-quote strings in debugging messages
+ * Fix foreach / break. Fixes #639
+ * Chargeable-User-Identifier should be "octets"
+ * Fix typo in mainconfig. Fixes #634
+ * More rlm_perl fixes. Fixes #635
+ * Free OpenSSL memory on clean exit.
+ * Fix <attr>[0] !* ANY - Was removing all instances of <attr>
+ * Fix case where multiple attributes were returned from LHS of
+ mapping, as with rlm_ldap. Fixes #652
+ * Fix corner case in cursor where using fr_cursor_next_by_da
+ after calling fr_cursor_remove may of resulted in a read of
+ uninitialised memory.
+ * Don't SEGV if all connections to a database server go away.
+ Fixes #651.
+ * Fix issue where <attr> -= <value> was not removing tagged
+ instances of <attr> equal to <value> (only untagged).
+ * Fix issue where tag values were not being set on attributes
+ created with unlang/ldap update blocks.
+ * Create rlm_sqlcounter attributes as integer64 types instead
+ of integer types, so large counter values can be specified.
+ * Fix issue where specifying a dynamic client IP addresss using
+ FreeRADIUS-Client-IPv6-Prefix or FreeRADIUS-Client-IP-Prefix
+ may have caused a validation error.
+ * Don't print two "&" for messages about attribute references
+
+FreeRADIUS 3.0.3 Mon 12 May 2014 15:30:00 EDT urgency=medium
+ Feature improvements
+ * Everything now builds with no warnings from the C compiler,
+ clang static analyzer, or cppcheck.
+ * rlm_ldap now supports defining the LDAP attribute name via
+ backticked expansion (i.e. shell command) in
+ RADIUS <-> LDAP mappings.
+ * rlm_ldap now supports older style generic attributes.
+ * dynamic expansions (e.g. "%{expr:1 + 2}" are now parsed
+ when the server starts. Syntax errors in the strings
+ are caught, and a descriptive error is printed.
+ * Static regular expressions (e.g. /a*b/) are now parsed
+ when the server starts. Syntax errors in the strings
+ are caught, and a descriptive error is printed.
+ * dynamic expansions are cached after being parsed. They are
+ no longer re-parsed at run-time for every request.
+ * regular expressions are now parsed and cached when the server
+ starts.
+ * Added the %{rest:} expansion to rlm_rest, which will send
+ a GET request to the URL passed as the format string.
+ Any body text will be written to the expansion buffer.
+ * rlm_rest now available as a debian package.
+ * When an 'if' condition statically evaluates to true/false,
+ unlang does more static optimization. For examples, see
+ src/tests/keywords/if-skip
+ * All modules are marked as safe for '-C', which lets the
+ dynamic expansion checks work in more situations.
+ * Added 'none' and 'custom' rlm_rest body types. 'custom'
+ allows sending of arbitrary expanded text and content-type
+ headers.
+ * Added "config" section to Perl. See mods-available/perl
+ * Added '%v' which expands to the server version - Patch
+ from Alan Buxey.
+ * more mis-matched casts are caught in "if" conditions,
+ and descriptive errors are printed.
+ * Support basic response validation in radclient. This allows
+ administrators to write local test cases for their
+ site-specific configurations.
+ * Removed radconf2xml and radmin "show client config" and
+ "show home_server config".
+ * Forbid running with vulnerable versions of OpenSSL.
+ See "allow_vulnerable_openssl" in the "security"
+ subsection of "radiusd.conf"
+ * Catch underlying "heartbleed" problem, so that nothing bad
+ happens even when using a vulnerable version of OpenSSL.
+ * Add locking API for sql_null, linelog, and detail modules,
+ which should improve performance and work around issues
+ on platforms with bad file locking.
+ * Allow DHCP NAKs to be delayed, via setting
+ reply:FreeRADIUS-Response-Delay = 1
+ * Allow tag and array references anywhere attributes
+ are allowed in "unlang".
+ * many enhancements to radsniff, including output
+ to collectd, ipv6 support and packet loss statistics.
+ * Many dictionary updates (ZTE, Brocade, Motorola).
+ * rlm_yubikey now automatically splits passwords from OTP
+ strings.
+ * The detail file reader is now threaded by default.
+ This should improve performance reading the files.
+
+ Bug fixes
+ * Fix xlat expression %{attribute[n]} so that it actually
+ returns the n'th attribute instead of the first one.
+ * Don't parse string on RHS of update {} when using unary
+ operators (!*). The RHS should always be ignored.
+ * Check for more optional functions in json-c so we can
+ Build with libjson0, which is the name of the json-c package
+ on debian/ubuntu.
+ * Fix issue in radmin where the main dictionaries would
+ not be loaded which, depending on the configuration, may
+ have caused validation errors.
+ * Fix handling of "%{reply:3GPP-*}"
+ * Fix rlm_perl garbage attributes
+ * Fix oracle SQL queries, which amongst other things still
+ used the old expansion format, which is no longer
+ supported/parsed.
+ * Truncate long format strings and error markers instead of
+ omitting them.
+ * Fix multiple attribute parsing in rlm_rest JSON.
+ * Don't crash in rlm_rest if connect_uri is commented out
+ in the configuration.
+ * Don't double-escape strings to / from Perl. You may need
+ to double-check your Perl scripts if they use "\" characters.
+ See mods-available/perl for documentation.
+ * Don't re-run "authorize" if a home server fails to respond.
+ * Don't append "0x" to hex output of octets types, for xlat
+ expansions. This is the same as v2, and makes it easier
+ to concatenate multiple attributes of type "octets"
+ * FreeBSD fixes for execinfo linking.
+ * Make some of the module configurations more consistent.
+ * Fix corner cases where STDOUT wouldn't be closed in
+ daemon mode.
+ * Re-enable "update coa" and originating CoA requests.
+ * Prevent multiple threads writing to the sql query logs.
+ * Fix zombie period calculation. Closes #579
+ * Properly parent VPs for talloc, when moving them in map2request.
+ * Various fixes for talloc parent / child relationships
+ * Allow rlm_counter to support VSAs.
+ * Normalize return codes for many modules. "do nothing" is noop,
+ not "ok".
+ * Run Post-Proxy-Type Fail. Closes #576
+ * Fix DHCP destination port for replies to relays. Closes #591
+ * Do-Not-Respond policy works again Closes #593
+ * Proxy-To-Virtual-Server works again. Closes #596
+ * Build fixes for ancient systems. Closes #607, #608, #609.
+ * %{Module-Return-Code} works again. Closes #610.
+ * Don't increment statistics for Status-Server responses.
+ Closes #612.
+ * A duplicate request isn't a duplicate if the original one
+ is marked "done". This should lower retransmissions from
+ clients.
+ * Fix multiple regular expression and glob memory leaks.
+ * Don't allocate any memory in fr_fault() as it can cause malloc
+ to deadlock.
+ * Temporarily set dumpable flag before calling system in fr_fault()
+ else the debugger may not be able to attach.
+ * Set nonblock on all TCP client sockets.
+ * Fix minor buffer overrun in mschapv2 where some attribute strings
+ were not correctly \0 terminated.
+ * Fix crash on authentication failure with MIT kerberos.
+ * Fix code so that octal escape sequences aren't prematurely unescaped
+ in rlm_sql, radclient, preprocess, and other places. This may
+ require configuration changes, as these sequences will no longer
+ need double escaping (\\) of the backslash.
+ * The connection pools no longer have one connection used twice
+ in certain rare conditions.
+ * Use self pipes for internal signals. The code was there, but was
+ unused.
+ * Don't crash if there are outstanding EAP sessions and were told to
+ exit gracefully.
+ * Fix typo in dictionary.rfc4072
+
+FreeRADIUS 3.0.2 Fri 21 Mar 2014 08:30:00 EDT urgency=medium
+ Feature improvements
+ * secret keys and LDAP / SQL passwords are now printed as
+ '<<< secret >>>' in debugging mode. Use -Xx to see the
+ actual passwords.
+ * Print out more information about passwords in -Xx,
+ including hashes, comparisons, etc.
+ * Allow cast (and implicit conversion) of integers to IPv4 addresses
+ * More xlats allow attribute references. This means they can
+ operate on binary data. e.g. expr, base64, md5, sha1.
+ * Added more tests.
+ * The dictionaries are now auto-loaded. raddb/dictionary
+ should no longer have $INCLUDE ${prefix}/share/dictionary
+ * A "panic_action" can be set to have the server dump a gdb
+ log on SEGV or other fatal error. See radiusd.conf
+ * Add support for SHA-224, SHA-256, SHA-384, SHA-512 to rlm_pap.
+ * Add "%{sha256:}" and "%{sha512:}" xlat functions.
+ * Cache CUI in EAP session resumption.
+ * templates can now have sub-sections, which will be included
+ in the section referencing the template.
+ * Update more dictionaries.
+ * Added more instances of the "always" module, for all return
+ codes.
+ * Suppress broken NASes when proxying. Retransmits which occur
+ more than once per second are rate-limited to once per second.
+ * Allow '&' in more xlat expansions.
+ * Update PostgreSQL schema and queries to record last updated
+ time, and accounting interim.
+ * Optimize more "if" conditions when the server loads. This will
+ avoid work at run time. e.g. ("foo" == "bar") --> FALSE.
+ * Allow removal of all attributes within a list with !* operator.
+ * Allow list to list copies with request qualifiers (outer.).
+ * Add support for ipv4 prefixes and ipv6 addresses and prefixes to
+ %{integer:}.
+ * allow radmin command "set module status <module> <code>"
+ which can be used to forcibly enable/disable modules.
+ * pap module now assumes Cleartext-Password if Password-With-Header
+ doesn't have a {...} header.
+ * Added "unpack" module. It can unpack binary data from horrible
+ VSA formats. See raddb/mods-available/unpack
+ * Added example IP Pool for DHCP, using sqlite. From Matthew Newton
+ See raddb/mods-config/sql/ippool-dhcp/
+
+ Bug fixes
+ * Fix SQL groups.
+ * Fix operation of fr_strerror() with RE*() macros.
+ * Don't assert if the connection we're trying to reconnect
+ is not in_use.
+ * Fix %{mschap:User-Name} xlat.
+ * Allow comparisons of signed integers and of ethernet addresses.
+ * Fix parsing of text-based ascend binary filters.
+ * Fix a few minor Coverity and clang analyzer issues.
+ * Log WARNING and ERROR prefixes only once, not twice.
+ * Fix attribute truncation seen in Perl and other places.
+ * Use correct port when DHCP relaying.
+ * Fix behaviour on FreeBSD where sending packets from an interface
+ bound to an IP address would fail when the server was built with
+ udpfromto.
+ * Don't abort() when freeing home servers on exit.
+ * Fix edge case in pairmove() when some attributes could be over-
+ written.
+ * Do checks for individual sqlite v2 functions so rlm_sqlite builds
+ correctly with more versions of the library.
+ * In heimdal kerberos, create MEMORY ccaches on a per context basis.
+ This prevents issues with the root ccache being used.
+ * Fix corner case with proxying, where home server goes down.
+ * Rate-limit "max_requests" complaint. We don't want to fill the
+ logs when something goes wrong.
+ * Use /dev/urandom for raddb/certs/random, if it exists.
+ * Issue WARNING that old-style clients should no longer be used.
+ * Auto-set secret to "radsec" for tcp+tls home servers.
+ * Fix double free in home_server_add when there is a parse error
+ on startup.
+ * rlm_unix checks if the dictionaries are broken, instead of crashing
+ * Fix potential memory corruption when normalising salted password
+ hashes from hex, where the combined hash and salt was > 64 bytes.
+ * Register sqlcounter attributes correctly, and other issues with it
+ * treat 127.0.0.1/32 as being identical to 127.0.0.1
+ * Don't mangle error output of SQL drivers like PostgreSQL
+ * Fix usage of "tls = ${tls}". It could previously cause problems
+ when the reference was used multiple times.
+ * Fix TLS session leak for incoming sockets.
+ * Try harder to clean up memory on exit when using "-mM"
+ * Fix memory leak when home server is down for RadSec connections
+ * rate-limit outgoing connection attempts when the home server
+ is down. It will retry no more than once per second.
+ * When parsing ipv6 address prefixes, always mask off the host
+ portion.
+ * Fix rlm_counter so that it does not create two reply
+ attributes.
+ * Fix issues with DHCP Sub-TLVs where the value of the first
+ Sub-TLV would appear corrupted, and subsequent TLVs would
+ not appear in debug output.
+ * Initialize scope in IP address parsing
+ * Prevent vendor attributes and RFC space attributes from clashing
+ in rlm_attr_filter.
+ * Set source IP address for DHCP packets from DHCP-Server-IP-Address,
+ or DHCP-DHCP-Server-Identifier, if we're unable to otherwise
+ determine the source IP.
+ * Fix POST attribute parsing in rlm_rest.
+ * Fix JSON attribute parsing in rlm_rest.
+ * Don't append trailing & to POST options in rlm_rest (minor).
+ * Process HTTP 100 Continue messages correctly in rlm_rest
+ * Fix generation of long > 512 byte POST payloads, where attribute
+ values on the chunk boundary may have been omitted in rlm_rest.
+ * Remove duplicate escape sequence parsing in rlm_sqlippool and
+ rlm_sqlcounter which caused issues with escaping %. Escape
+ sequence parsing is now handled purely by the xlat functions.
+ * Ensure %% is treated as a string literal, and so not passed to any
+ xlat escape functions for processing.
+ * Correct calculation of Message-Authenticator
+ for CoA packets. Closes #556
+
FreeRADIUS 3.0.1 Mon 13 Jan 2014 14:30:00 EDT urgency=medium
Feature improvements
* Add "timeout" to exec, and "ntlm_auth_timeout" to mschap.
realm\username
The realm parsing syntax ( and search order ) is user definable via the
-realm module config in the ``/etc/raddb/radiusd.conf`` configuration file.
+realm module config in the ``/etc/raddb/mods-available/realm`` configuration
+file.
You can define multiple instances of the realm module to support multiple
realm syntax's at the same time. Be sure to pay close attention to the
If you set the remote server to ``LOCAL``, the request will be handled
locally as usual, without sending it to a remote radius server.
-There are several options you can add in both files:
+There are several options you can add in ``/etc/raddb/proxy.conf``:
- nostrip:
By default the realm is stripped from the username before sending it
|%V |Request-Authenticator | |
| |(Verified/None) | |
+-----------+---------------------------+-----------------------+
+|%v |Server Version | |
++-----------+---------------------------+-----------------------+
|%Y |request year (YYYY) | |
+-----------+---------------------------+-----------------------+
|%Z |All request attributes | |
+++ /dev/null
-Submitting patches or diff's to the FreeRADIUS project
-======================================================
-
-For a person or company wishing to submit a change to the
-FreeRADIUS project, the process can sometimes be daunting if you're
-not familiar with "the system." This text is a collection of
-suggestions which can greatly increase the chances of your change
-being accepted.
-
-Only trivial patches will be accepted via email.
-Large patches, or patches that modify a number of files MUST be
-submitted as a pull-request via GitHub.
-
-See the following for more details:
- - https://help.github.com/articles/fork-a-repo
- - http://wiki.freeradius.org/contributing/GitHub
-
-
-Submitting patches via email
-----------------------------
-
- 1. "diff -u"
-
- Use "diff -u" or "diff -urN" to create patches.
-
- All changes to the source occur in the form of patches, as
- generated by diff(1). When creating your patch, make sure to
- create it in "unified diff" format, as supplied by the '-u'
- argument to diff(1). Patches should be based in the root source
- directory, not in any lower subdirectory.
-
- To create a patch for a single file, it is often sufficient to do:
-
- SRCTREE=/home/user/src/freeradiusd/
- MYFILE=src/modules/rlm_foo/foo.c
-
- cd $SRCTREE
- cp $MYFILE $MYFILE.orig
- vi $MYFILE # make your change
- diff -u $MYFILE.orig $MYFILE > /tmp/patch
-
- To create a patch for multiple files, you should unpack a
- "vanilla", or unmodified source tree, and generate a diff
- against your own source tree. For example:
-
- MYSRC=/home/user/src/freeradiusd-feature/
-
- gunzip freeradiusd-version.tar.gz
- tar xvf freeradiusd-version.tar
- diff -urN freeradiusd-version $MYSRC > ~/feature-version.patch
-
- 2. Describe your changes.
-
- Describe the technical detail of the change(s) your patch includes.
-
- Be as specific as possible. The WORST descriptions possible
- include things like "update file X", "bug fix for file X",
- or "this patch includes updates for subsystem X. Please apply."
-
- If your description starts to get long, that's a sign that you
- probably need to split up your patch. See #3, next.
-
- 3. Separate your changes.
-
- Separate each logical change into its own patch.
-
- For example, if your changes include both bug fixes and
- performance enhancements for a single module, separate those
- changes into two or more patches.
-
- On the other hand, if you make a single change to numerous
- files, group those changes into a single patch. Thus a single
- LOGICAL change is contained within a single patch.
-
- If one patch depends on another patch in order for a change to
- be complete, that is OK. Simply note "this patch depends on
- patch X" in your patch description.
-
- 4. Select e-mail destination.
-
- If you are on the developers mailing list, send the patch there.
- freeradius-devel@lists.freeradius.org
-
- Otherwise, send the patch to 'patches@freeradius.org'
-
- 5. No MIME, no links, no compression, no attachments. Just plain text.
-
- The developers need to be able to read and comment on the
- changes you are submitting. It is important for a developer to
- be able to "quote" your changes, using standard e-mail tools, so
- that they may comment on specific portions of your code.
-
- For this reason, all patches should be submitting e-mail
- "inline".
-
- Do not attach the patch as a MIME attachment, compressed or
- not. Many popular e-mail applications will not always transmit a
- MIME attachment as plain text, making it impossible to comment
- on your code. A MIME attachment also takes a bit more time to
- process, decreasing the likelihood of your MIME-attached change
- being accepted.
-
- Compressed patches are generally rejected outright. If the
- developer has to do additional work to read your patch, the odds
- are that it will be ignored completely.
-
- 6. E-mail size.
-
- When sending patches, always follow step #5.
-
- Large changes are not appropriate for mailing lists, and some
- maintainers. If your patch, exceeds 40Kb in size, it is
- preferred that you store your patch on an Internet-accessible
- server, and provide instead a URL (link) pointing to your patch.
-
- 7. Name the version of the server.
-
- It is important to note, either in the subject line or in the
- patch description, the server version to which this patch
- applies.
-
- 8. Don't get discouraged. Re-submit.
-
- After you have submitted your change, be patient and wait. If
- the patch is approved and applied, it will appear in the next
- version of the server.
-
- However, if your change doesn't appear in the next version of
- the server, there could be any number of reasons. It's YOUR job
- to narrow down those reasons, correct what was wrong, and submit
- your updated change.
-
- It is quite common a patch to be "dropped" without
- comment. That's the nature of the system. If your patch is
- dropped, it could be due to
-
- A style issue (see section 2, below),
- An e-mail formatting issue (see section item 5, above)
- A technical problem with your change
- Your patch got lost among other patches
-
- When in doubt, re-submit.
--- /dev/null
+Submitting patches or diff's to the FreeRADIUS project
+======================================================
+
+For a person or company wishing to submit a change to the FreeRADIUS project the process can sometimes be daunting if
+you're not familiar with "the system." This text is a collection of suggestions which can greatly increase the chances
+of your change being accepted.
+
+Note: Only trivial patches will be accepted via email. Large patches, or patches that modify a number of files MUST be
+submitted as a pull-request via GitHub.
+
+Hints and tips
+--------------
+
+1. Describe your changes
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Describe the technical detail of the change(s) your patch or commit includes.
+
+Be as specific as possible. The WORST descriptions possible include things like "update file X", "bug fix for file X",
+or "this patch includes updates for subsystem X. Please apply."
+
+If your description starts to get long, that's a sign that you probably need to split up your commit. See #3, next.
+
+2. Separate your changes
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Separate each logical change into its own commit.
+
+For example, if your changes include both bug fixes and performance enhancements for a single module, separate those
+changes into two or more patches.
+
+On the other hand, if you make a single change to numerous files, group those changes into a single commit.
+Thus a single LOGICAL change is contained within a single commit.
+
+If one commit depends on another commit in order for a change to be complete, that is OK. Simply note "this commit
+depends on commit X" in the extended commit description.
+
+If your commit includes significant whitespace changes these should also be broken out into another, separate, commit.
+
+Submitting patches via GitHub
+-----------------------------
+
+See the following links for more details about submitting via github:
+
+- https://help.github.com/articles/fork-a-repo
+- http://wiki.freeradius.org/contributing/GitHub
+
+Submitting patches via email
+----------------------------
+
+1. "diff -u"
+~~~~~~~~~~~~
+Use ``diff -u`` or ``diff -urN`` to create patches.
+
+All changes to the source occur in the form of patches, as generated by diff(1). When creating your patch, make sure to
+create it in "unified diff" format, as supplied by the '-u' argument to diff(1). Patches should be based in the root
+source directory, not in any lower subdirectory.
+
+To create a patch for a single file, it is often sufficient to do::
+
+ SRCTREE=/home/user/src/freeradiusd/
+ MYFILE=src/modules/rlm_foo/foo.c
+
+ cd $SRCTREE
+ cp $MYFILE $MYFILE.orig
+ vi $MYFILE # make your change
+ diff -u $MYFILE.orig $MYFILE > /tmp/patch
+
+To create a patch for multiple files, you should unpack a "vanilla", or unmodified source tree, and generate a diff
+against your own source tree. For example::
+
+ MYSRC=/home/user/src/freeradiusd-feature/
+
+ gunzip freeradiusd-version.tar.gz
+ tar xvf freeradiusd-version.tar
+ diff -urN freeradiusd-version $MYSRC > ~/feature-version.patch
+
+
+2. Select e-mail destination
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you are on the developers mailing list, send the patch there. freeradius-devel@lists.freeradius.org
+
+Otherwise, send the patch to 'patches@freeradius.org'
+
+3. No MIME, no links, no compression, no attachments. Just plain text
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The developers need to be able to read and comment on the changes you are submitting. It is important for a developer
+to be able to "quote" your changes, using standard e-mail tools, so that they may comment on specific portions of your
+code.
+
+For this reason, all patches should be submitting e-mail "inline".
+
+Do not attach the patch as a MIME attachment, compressed or not. Many popular e-mail applications will not always
+transmit a MIME attachment as plain text, making it impossible to comment on your code. A MIME attachment also takes
+a bit more time to process, decreasing the likelihood of your MIME-attached change being accepted.
+
+Compressed patches are generally rejected outright. If the developer has to do additional work to read your patch,
+the odds are that it will be ignored completely.
+
+4. E-mail size
+~~~~~~~~~~~~~~
+
+Large changes are not appropriate for mailing lists, and some maintainers. If your patch, exceeds 5Kb in size, you
+must submit the patch via GitHub instead.
+
+5. Name the version of the server
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It is important to note, either in the subject line or in the patch description, the server version to which this patch
+applies.
#this is the basedn to do searches on a user
basedn = ou=users,ou=radius,dc=mydomain,dc=com
#notice the username is the stripped user-name or user-name
- filter = (uid=%{Stripped-User-Name:-{User-Name}})
+ filter = (uid=%{%{Stripped-User-Name}:-%{User-Name}})
start_tls = no
tls_mode = no
#this maps ldap attributetypes to radius attributes
#with --with-edir option.
#edir_account_policy_check=no
groupname_attribute = radiusGroupName
- groupmembership_filter = (&(uid=%{Stripped-User-Name:-%{User-Name}})
+ groupmembership_filter = (&(uid=%{%{Stripped-User-Name}:-%{User-Name}})
(objectclass=radiusprofile))
groupmembership_attribute = radiusGroupName
timeout = 3
identity = "uid=freeradius,ou=admins,ou=radius,dc=mydomain,dc=com"
password = example
basedn = "ou=users,ou=radius,dc=mydomain,dc=com"
- filter = "(&(uid=%{Stripped-User-Name:-%{User-Name}})
+ filter = "(&(uid=%{%{Stripped-User-Name}:-%{User-Name}})
(objectclass=radiusprofile)"
start_tls = no
tls_mode = no
#password_header = "{clear}"
password_attribute = userPassword
groupname_attribute = radiusGroupName
- groupmembership_filter = "(&(uid=%{Stripped-User-Name:-%{User-Name}}))
+ groupmembership_filter = "(&(uid=%{%{Stripped-User-Name}:-%{User-Name}}))
(objectclass=radiusProfile)"
groupmembership_attribute = radiusGroupName
timeout = 3
This release adds support for Microsoft Statement-of-Health (SoH), which is
a form of network access protection.
-Client supprot is present in Windows XP SP3, Vista and 7.
+Client support is present in Windows XP SP3, Vista and 7.
SoH data can come in from several places:
TYPEDEF_HIDES_STRUCT = YES
-# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
-# determine which symbols to keep in memory and which to flush to disk.
-# When the cache is full, less often used symbols will be written to disk.
-# For small to medium size projects (<1000 input files) the default value is
-# probably good enough. For larger projects a too small cache size can cause
-# doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penalty.
-# If the system has enough physical memory increasing the cache will improve the
-# performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will roughly double the
-# memory usage. The cache size is given by this formula:
-# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols
-
-SYMBOL_CACHE_SIZE = 4
-
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
SHOW_USED_FILES = YES
-# If the sources in your project are distributed over multiple directories
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
-# in the documentation. The default is NO.
-
-SHOW_DIRECTORIES = YES
-
# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
# This will remove the Files entry from the Quick Index and from the
# Folder Tree View (if specified). The default is YES.
HTML_TIMESTAMP = YES
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-
-HTML_ALIGN_MEMBERS = YES
-
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the
# page has loaded. For this to work a browser that supports
GENERATE_TREEVIEW = NO
-# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
-# and Class Hierarchy pages using a tree view instead of an ordered list.
-
-USE_INLINE_TREES = YES
-
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
# used to set the initial width (in pixels) of the frame in which the tree
# is shown.
# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-DOT_GRAPH_MAX_NODES = 50
+DOT_GRAPH_MAX_NODES = 100
# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
# graphs generated by dot. A depth value of 3 means that only nodes reachable
# code bases. Also note that the size of a graph can be further restricted by
# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-MAX_DOT_GRAPH_DEPTH = 0
+MAX_DOT_GRAPH_DEPTH = 4
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
# background. This is disabled by default, because dot on Windows does not
-.TH RADCLIENT 1 "2 April 2009" "" "FreeRADIUS Daemon"
+.TH RADCLIENT 1 "28 March 2014" "" "FreeRADIUS Daemon"
.SH NAME
radclient - send packets to a RADIUS server, show reply
.SH SYNOPSIS
.B radclient
.RB [ \-4 ]
.RB [ \-6 ]
-.RB [ \-d
-.IR raddb_directory ]
.RB [ \-c
.IR count ]
+.RB [ \-d
+.IR raddb_directory ]
+.RB [ \-D
+.IR dictionary_directory ]
.RB [ \-f
.IR file ]
.RB [ \-F ]
.IP \-c\ \fIcount\fP
Send each packet \fIcount\fP times.
.IP \-d\ \fIraddb_directory\fP
-The directory that contains the RADIUS dictionary files. Defaults to
+The directory that contains the user dictionary file. Defaults to
\fI/etc/raddb\fP.
-.IP \-f\ \fIfile\fP
+.IP \-D\ \fIdictionary_directory\fP
+The directory that contains the main dictionary file. Defaults to
+\fI/usr/share/freeradius\fP.
+.IP \-f\ \fIfile[:file]\fP
File to read the attribute/value pairs from. If this is not specified,
they are read from stdin. This option can be specified multiple
times, in which case packets are sent in order by file, and within
each file, by first packet to last packet. A blank line separates
-logical packets within a file.
+logical packets within a file. If a pair of files separated by a
+colon is specified, the second file will be used to filter the
+responses to requests from the first. The number of requests and
+filters must be the same. A summary of filter results will be displayed
+if -s is passed.
.IP \-F
Print the file name, packet number and reply code.
.IP \-h
file, set this option to 'cistron'.
.IP key
This option lets you set the attribute to use as a key to find
-entries. The default is "%{Stripped-User-Name:-%{User-Name}}". Note
+entries. The default is "%{%{Stripped-User-Name}:-%{User-Name}}". Note
that the key MUST supply real data. Dynamic attributes like "Group"
will not work, because the "Group" attribute can only be used as a
comparison, to see if a user is in a Unix group. It will not return
the name of the Unix group that a user is in.
.PP
-If you want to use groups as a key, see the \fIrlm_passed\fP, which
+If you want to use groups as a key, see the \fIrlm_passwd\fP, which
will create a real attribute that contains the group name.
.PP
This configuration entry enables you to have configurations that
.br
compat = no
.br
- key = %{Stripped-User-Name:-%{User-Name}}
+ key = %{%{Stripped-User-Name}:-%{User-Name}}
.br
}
.br
.RE
.sp
..
-.TH rlm_pap 5 "6 June 2008" "" "FreeRADIUS Module"
+.TH rlm_pap 5 "17 April 2014" "" "FreeRADIUS Module"
.SH NAME
rlm_pap \- FreeRADIUS Module
.SH DESCRIPTION
.SH CONFIGURATION
.PP
The only relevant configuration item is:
-.IP auto_header
-If set to "yes", the module will look inside of the User-Password
-attribute for the headers {crypt}, {clear}, etc., and will
-automatically create the appropriate attribute, with the correct
-value.
+.IP normify
+The default is "yes". This means that the module will try to convert
+hex passwords and base64-encoded passwords to "normalized" form.
+However, some clear text passwords may be erroneously converted.
+Setting this to "no" prevents that conversion.
.PP
-This module understands many kinds of password hashing methods, as
-given by the following table.
+The module looks for the Password-With-Header attribute to find the
+"known good password. The header is given by the following table.
.PP
.DS
.br
strings, and binary data, and convert them to a format that the server
can use.
.PP
+If there is no Password-With-Header attribute, the module looks for
+Cleartext-Password, NT-Password, Crypt-Password, etc.
+.PP
It is important to understand the difference between the User-Password
and Cleartext-Password attributes. The Cleartext-Password attribute
is the "known good" password for the user. Simply supplying the
.RE
.sp
..
-.TH unlang 5 "16 July 2013" "" "FreeRADIUS Processing un-language"
+.TH unlang 5 "15 April 2014" "" "FreeRADIUS Processing un-language"
.SH NAME
unlang \- FreeRADIUS Processing un\-language
.SH DESCRIPTION
.DE
.IP foreach
.br
-Loops over a named variable, running the block for each copy of the
-named variable. The return value of the block is the return value of
-the last statement executed. The loop can be exited early by using
-the "break" keyword. Unlike other languages, "break" here means "exit
-the loop at the next iteration", not "exit the loop now". The result
-is that any statements after the "break" keyword will still be
-executed. We recommend using "break" only when it is the last
-statement in a "foreach" block.
-
-The attribute name is just the name, e.g. reply:Reply-Message, with
-none of the usual variable referenced %{...}. This is because it is a
-reference to the attribute, and not an expansion of the attribute.
+Loops over values of an attribute, running the block for each value.
+The return value of the block is the return value of the last
+statement executed. The loop can be exited early by using the "break"
+keyword. Unlike other languages, "break" here means "exit the loop at
+the next iteration", not "exit the loop now". The result is that any
+statements after the "break" keyword will still be executed. We
+recommend using "break" only when it is the last statement in a
+"foreach" block.
Inside of the "foreach" block, the attribute which is being looped
over can be referenced as "Foreach-Variable-#". Where "#" is the
recommended.
.DS
- foreach Attribute-Name {
+ foreach &Attribute-Reference {
.br
...
.br
.DE
.IP switch
.br
-Evaluate the given string, and choose the first matching "case"
-statement inside of the current block. If the string is surrounded by
-double quotes, it is expanded as described in the DATA TYPES section,
-below.
+A "switch" statement takes one argument, and contains a series of
+"case" statements. When a "switch" statement is encountered, the
+argument from the "switch" is evaluated in turn against the argument
+from each "case" statement. The first "case" statement which matches
+is executed. All other "case" statements are ignored. A default
+"case" statement can be defined, by omitting its argument.
+
+If the argument is a double quoted string (e.g. "%{exec:1 + 2}", it is
+expanded as described in the DATA TYPES section, below. The match is
+then performed on the string returned from the expansion. If the
+argument is an attribute reference (e.g. &User-Name), then the match
+is performed on the value of that attribute. Otherwise, the argument
+is taken to be a literal string, and and matching is done via simple
+comparison.
No statement other than "case" can appear in a "switch" block.
.DS
- switch "string" {
+ switch <argument> {
.br
...
.br
.DE
.IP case
.br
-Define a static string to match a parent "switch" statement. The
-strings given here are not expanded as is done with the parent
-"switch" statement.
+Provides a place-holder which matches the argument of a parent
+"switch" statment.
A "case" statement cannot appear outside of a "switch" block.
+If the argument is a double quoted string (e.g. "%{exec:1 + 2}", it is
+expanded as described in the DATA TYPES section, below. The match is
+then performed on the string returned from the expansion. If the
+argument is an attribute reference (e.g. &User-Name), then the match
+is performed on the value of that attribute. Otherwise, the argument
+is taken to be a literal string, and and matching is done via simple
+comparison.
+
.DS
- case string {
+ case <argument> {
.br
...
.br
}
.DE
-A default entry can be defined by omitting the static string. This
-entry will be used if no other "case" entry matches. Only one default
-entry can exist in a "switch" section.
+A default entry can be defined by omitting the argument, as given
+below. This entry will be used if no other "case" entry matches.
+Only one default entry can exist in a "switch" section.
.DS
case {
.DS
update <list> {
.br
- attribute = value
+ Attribute-Reference = value
.br
...
.br
The only contents permitted in an "update" section are attributes and
values. The contents of the "update" section are described in the
-ATTRIBUTES section below.
+ATTRIBUTE REFERENCE and ATTRIBUTE ASSIGNMENT sections below.
.IP redundant
This section contains a simple list of modules. The first module is
called when the section is being processed. If the first module
.br
}
.DE
+.SH ATTRIBUTE REFERENCES
+
+Attributes may be referenced via the following syntax:
+.DS
+ Attribute-Name
+ Attribute-Name:TAG
+ Attribute-Name[NUM]
+ <list>:Attribute-Name
+ <list>:Attribute-Name:TAG[NUM]
+.DE
+Where <list> is one of "request", "reply", "control", "proxy-request",
+"proxy-reply", or "outer.request", "outer.reply", "outer.control",
+"outer.proxy-request", or "outer.proxy-reply". just as with the
+"update" section, above. The "<list>:" prefix is optional, and if
+omitted, is assumed to refer to the "request" list.
+
+The TAG portion is a decimal integer between 1 and 31. Please see RFC
+2868 for more information about tags. Tags can only be used for
+attributes which are marked in the dictionary as "has_tag".
+
+The NUM portion is used when there are multiple attributes of the same
+name in a list. The "Attribute-Name" reference will return the first
+attribute. Using an array offset allows the policy to refer to the
+second and subsequent attributes.
+
+When an attribute name is encountered, the given list is examined for
+an attribute of the given name. Some examples are:
+.DS
+ User-Name
+.br
+ request:User-Name # same as above
+.br
+ reply:User-Name
+.br
+ Tunnel-Password:1
+.br
+ Cisco-AVPAir[2]
+.br
+ outer.request:User-Name # from inside of a TTLS/PEAP tunnel
+.DE
+Note that unlike C, there is no way to define new attributes at
+run-time. They MUST be declared in a dictionary file, and loaded when
+the server starts.
+
+All attributes are defined in the dictionaries that accompany the
+server. These definitions define only the name and type, and do not
+define the value of the attribute. When the server receives a packet,
+it uses the packet contents to look up entries in the dictionary, and
+instantiates attributes with a name taken from the dictionaries, and a
+value taken from the packet contents. This process means that if an
+attribute does not exist, it is usually because it was not contained
+in a packet that the server received.
+
+Once the attribute is instantiated, it is added to a list. It can
+then be referenced, updated, replaced, etc.
+
.SH CONDITIONS
The conditions are similar to C conditions in syntax, though
quoted strings are supported, as with the Unix shell.
Where the left-hand side is an attribute, the "&" can be omitted.
However, it is allowed for completeness. e.g. The comparison
"(&User-Name == &Filter-Id)" is equivalent to the example above.
+
+We recommend using attribute references instead of printing
+attributes to a string, via (User-Name == "%{Filter-Id}").
+Attribute references will be faster and more efficient.
+
.RE
.IP Casts
.DS
.IP """strings"""
.RS
Double-quoted strings are expanded by inserting the value of any
-variables (see VARIABLES, below) before being evaluated. If
+attributes (see VARIABLES, below) before being evaluated. If
the result is a number it is evaluated in a numerical context.
String length is limited by line-length, usually about 8000
shells.
Note that for security reasons, the input string is split into command
-and arguments before variable expansion is done.
+and arguments before string expansion is done.
For performance reasons, we suggest that the use of back-quoted
strings be kept to a minimum. Executing external programs is
If the comparison operator is "=~", then parantheses in the regular
expression will define variables containing the matching text, as
described below in the VARIABLES section.
-.SH VARIABLES
-Run-time variables are referenced using the following syntax
+.SH EXPANSIONS
+Attributes are expanded using the ATTRIBUTE REFERENCE syntax
+described above, and surrounding the reference with "%{...}"
.DS
- %{Variable-Name}
+ %{Attribute-Reference}
.DE
-Note that unlike C, there is no way to declare variables, or to refer
-to them outside of a string context. All references to variables MUST
-be contained inside of a double-quoted or back-quoted string.
-
-Many potential variables are defined in the dictionaries that
-accompany the server. These definitions define only the name and
-type, and do not define the value of the variable. When the server
-receives a packet, it uses the packet contents to look up entries in
-the dictionary, and instantiates variables with a name taken from the
-dictionaries, and a value taken from the packet contents. This
-process means that if a variable does not exist, it is usually because
-it was not mentioned in a packet that the server received.
-
-Once the variable is instantiated, it is added to an appropriate
-attribute list, as described below. In many cases, attributes and
-variables are inter-changeble, and are often talked about that way.
-However, variables can also refer to run-time calls to modules, which
-may perform operations like SQL SELECTs, and which may return the
-result as the value of the variable.
-.PP
-Referencing attribute lists
-.RS
-Attribute lists may be referenced via the following syntax
-
-.DS
- %{<list>:Attribute-Name}
-.DE
-
-Where <list> is one of "request", "reply", "control", "proxy-request",
-"proxy-reply", or "outer.request", "outer.reply", "outer.control",
-"outer.proxy-request", or "outer.proxy-reply". just as with the
-"update" section, above. The "<list>:" prefix is optional, and if
-omitted, is assumed to refer to the "request" list.
-
-When a variable is encountered, the given list is examined for an
-attribute of the given name. If found, the variable reference in the
-string is replaced with the value of that attribute. Some examples are:
-
-.DS
- %{User-Name}
-.br
- %{request:User-Name} # same as above
-.br
- %{reply:User-Name}
-.br
- %{outer.request:User-Name} # from inside of a TTLS/PEAP tunnel
-.DE
-.RE
+The result will be a string which contains the value of the attribute
+which was referenced, as a printable string. If the attribute does
+not exist, the result will be an empty string.
.PP
Results of regular expression matches
.RS
.RS
It is useful to query a database for some information, and to use the
result in a condition. The following syntax will call a module, pass
-it the given string, and replace the variable reference with the
+it the given string, and replace the string expansion with the
resulting string returned from the module.
.DS
e.g. If a request contains "Framed-IP-Address = 127.0.0.1", the expansion
of %{hex:Framed-IP-Address} will yeild "0x7f000001".
-.IP %{Attribute-Name[index]}
-Reference the N'th occurance of the given attribute. The syntax
-%{<list>:Attribute-Name[index]} may also be used. The indexes start
-at zero. This feature is NOT available for non-attribute dynamic
-translations, like %{sql:...}.
-
-For example, %{User-Name[0]} is the same as %{User-Name}
-
-The variable %{Cisco-AVPair[2]} will reference the value of the
-THIRD Cisco-AVPair attribute (if it exists) in the request packet,
-.IP %{Attribute-Name[#]}
-Returns the total number of attributes of that name in the relevant
-attribute list. The number will usually be between 0 and 200.
-
-For most requests, %{request:User-Name[#]} == 1
-.IP %{Attribute-Name[*]}
-Expands to a single string, with the value of each array
-member separated by a newline.
-.IP %{#Attribute-Name[index]}
-Expands to the length of the string %{Attribute-Name[index]}.
-.SH ATTRIBUTES
+.SH ATTRIBUTE ASSIGNMENTS
The attribute lists described above may be edited by listing one or
more attributes in an "update" section. Once the attributes have been
defined, they may be referenced as described above in the VARIABLES
file. There is no need for commas or semi-colons after the value.
.DS
- Attribute-Name = value
+ Attribute-Reference = value
.DE
.PP
-Attribute names
+Attribute Reference
.RS
-The Attribute-Name must be a name previously defined in a dictionary.
-If an undefined name is used, the server will return an error, and
-will not start.
+The Attribute-Reference must be a reference (see above), using a name
+previously defined in a dictionary. If an undefined name is used, the
+server will return an error, and will not start.
-The names can be qualified with a list prefix. For example,
-"request:User-Name" is usually a synonym for "User-Name".
.RE
.IP Operators
The operator used to assign the value of the attribute may be one of
"User-Name := &NAS-Port" is invalid, because "User-Name" is a string,
and "NAS-Port" is an integer.
+We recommend using the form "Attribute-1 = &Attribute-2" for updates,
+instead of "Attribute-1 = "%{Attribute-2}". The first version will
+copy the attribute data, no matter what its form. The second
+version will print the Attribute-2 to a string, and then parse it to
+create the value for Attribute-1. This second version is slower
+and more fragile than the first one.
+
When the value is an attribute-specific string, it can be a string,
integer, IP address, etc. The value may be expanded as described
above in the DATA TYPES section, above. For example, specifying
or by having the address returned as the output of a program that is
executed.
-When string values are finally assigned to a variable, they can have a
+When string values are finally assigned to an attribute, they can have a
maximum length of 253 characters. This limit is due in part to both
protocol and internal server requirements. That is, the strings in
the language can be nearly 8k in length, say for a long SQL query.
+++ /dev/null
-.TH RADCONF2XML 8
-.SH NAME
-radconf2xml - converts radiusd.conf to XML
-.SH SYNOPSIS
-.B radconf2xml
-.RB [ \-d
-.IR raddb_dir ]
-.RB [ \-h ]
-.RB [ \-n
-.IR name ]
-.RB [ \-o
-.IR out_file ]
-
-.SH DESCRIPTION
-\fBradconf2xml\fP reads the radiusd configuration file specified by
-\fIraddb_dir\fP/\fIname\fP.conf and converts it to XML format.
-The result is written to \fIout_file\fP which by default is stdout.
-
-.SH OPTIONS
-
-.IP \-d\ \fIraddb_dir\fP
-The radius configuration directory (typically /etc/raddb).
-.IP \-d\ \fIname\fP
-The name of the configuration file without the .conf extension.
-Defaults to radiusd.
-.IP \-h
-Print usage help information.
-.IP \-d\ \fIout_file\fP
-The output file the XML formatted file will be written to.
-Defaults to stdout.
-
-.SH SEE ALSO
-radiusd(8),
-.SH AUTHORS
-Alan DeKok <aland@deployingradius.com>
the UNIX \fI/etc/passwd\fP file. However it is also possible to define all
users, and their passwords, in this file.
.SH SEE ALSO
-rradiusd.conf(5), users(5), huntgroups(5), hints(5),
+radiusd.conf(5), users(5), huntgroups(5), hints(5),
dictionary(5), raddebug(8)
.SH AUTHOR
The FreeRADIUS Server Project (http://www.freeradius.org)
Upgrading to Version 3.0
========================
-The configuration for 3.0 is *largely* compatible with the 2.x.x
-configuration. However, it is NOT possible to simply use the 2.x.x
-configuration as-is. Instead, you should re-create it.
+.. contents:: Sections
+ :depth: 2
+
+.. important::
+ The configuration for 3.0 is *largely* compatible with the 2.x.x
+ configuration. However, it is NOT possible to simply use the 2.x.x
+ configuration as-is. Instead, you should re-create it.
Security
--------
status_server
These entries should be moved from "radiusd.conf" to the "security"
-subsection of that file
-
-Modules Directory
------------------
-
-As of version 3.0, the ``modules/`` directory no longer exists.
-
-Instead, all "example" modules have been put into the
-``mods-available/`` directory. Modules which can be loaded by the
-server are placed in the ``mods-enabled/`` directory. All of the
-modules in that directory will be loaded. This means that the
-"instantiate" section of radiusd.conf is less important.
-
-Modules can be enabled by creating a soft link. For module ``foo``, do::
-
- $ cd raddb
- $ ln -s mods-available/foo mods-enabled/foo
-
-To create "local" versions of the modules, we suggest copying the file
-instead. This leaves the original file (with documentation) in the
-``mods-available/`` directory. Local changes should go into the
-``mods-enabled/`` directory.
-
-Module-specific configuration files are now in the ``mods-config/``
-directory. This change allows for better organization, and means that
-there are fewer files in the main ``raddb`` directory. See
-``mods-config/README.rst`` for more details.
+subsection of that file.
Naming
------
The configuration items ``file``, ``script_file``, ``module``,
``detail``, ``detailfile``, ``attrsfile``, ``perm``, ``dirperm``,
-``detailperm``, and ``hostname`` are deprecated. As well as any
-faux portmanteaus, and configuration items that used hyphens
-as word delimiters.
-Please update your module configuration to use the new syntax.
+``detailperm``, and ``hostname`` are deprecated. As well as any false
+portmanteaus, and configuration items that used hyphens as word
+delimiters. e.g. ``foo-bar`` has been changed to ``foo_bar``. Please
+update your module configuration to use the new syntax.
In most cases the server will tell you the replacement config item to
use. As always, run the server in debugging mode to see these
messages.
+Modules Directory
+-----------------
+
+As of version 3.0, the ``modules/`` directory no longer exists.
+
+Instead, all "example" modules have been put into the
+``mods-available/`` directory. Modules which can be loaded by the
+server are placed in the ``mods-enabled/`` directory. All of the
+modules in that directory will be loaded. This means that the
+``instantiate`` section of radiusd.conf is less important. The only
+reason to list a module in the ``instantiate`` section is to force
+ordering when the modules are loaded.
+
+Modules can be enabled by creating a soft link. For module ``foo``, do::
+
+ $ cd raddb
+ $ ln -s mods-available/foo mods-enabled/foo
+
+To create "local" versions of the modules, we suggest copying the file
+instead. This leaves the original file (with documentation) in the
+``mods-available/`` directory. Local changes should go into the
+``mods-enabled/`` directory.
+
+Module-specific configuration files are now in the ``mods-config/``
+directory. This change allows for better organization, and means that
+there are fewer files in the main ``raddb`` directory. See
+``mods-config/README.rst`` for more details.
+
+Changed Modules
+---------------
+
+The following modules have been changed.
+
+
rlm_sql
--------
+~~~~~~~
The SQL configuration has been moved from ``sql.conf`` to
``mods-available/sql``. The ``sqlippool.conf`` file has also been
between the configuration items is::
num_sql_socks -> pool { max }
- connect_failure_retry_delay -> NOT SUPPORTED
+ connect_failure_retry_delay -> pool { retry_delay }
lifetime -> pool { lifetime }
max_queries -> pool { uses }
driver = rlm_sql_null
This is an empty driver which will always return "success". It is
-intended to be used to replace the ``sql_log`` module, and in
+intended to be used to replace the ``sql_log`` module, and to work in
conjunction with the ``radsqlrelay`` program. Simply take your normal
configuration for raddb/mods-enabled/sql, and set::
driver = rlm_sql_null
...
- logfile = ${radacctdir}/log.sql
+ logfile = ${radacctdir}/sql.log
-And all of the SQL queries will be logged to that file. The
-connection pool will still need to be configured for the NULL SQL
-driver, but the defaults will work.
+All of the SQL queries will be logged to that file. The connection
+pool does not need to be configured for the ``null`` SQL driver. It
+can be left as-is, or deleted from the SQL configuration file.
rlm_sql_sybase
---------------
+~~~~~~~~~~~~~~
The ``rlm_sql_sybase`` module has been renamed to ``rlm_sql_freetds``
and the old ``rlm_sql_freetds`` module has been removed.
``rlm_sql_sybase`` used the newer ct-lib API, and ``rlm_sql_freetds``
-used and older API and was incomplete.
+used an older API and was incomplete.
The new ``rlm_sql_freetds`` module now also supports database
selection on connection startup so ``use`` statements no longer
have to be included in queries.
sql/dialup.conf
----------------
+~~~~~~~~~~~~~~~
Queries for post-auth and accounting calls have been re-arranged. The
SQL module will now expand the 'reference' configuration item in the
3.0 module by adding the following::
accounting {
- reference = "%{tolower:type.%{Acct-Status-Type}.query}"
- type {
- accounting-on {
- query = "${....accounting_onoff_query}"
- }
- accounting-off {
- query = "${....accounting_onoff_query}"
- }
- start {
- query = "${....accounting_start_query}"
- query = "${....accounting_start_query_alt}"
- }
- interim-update {
- query = "${....accounting_update_query}"
- query = "${....accounting_update_query_alt}"
- }
- stop {
- query = "${....accounting_stop_query}"
- query = "${....accounting_stop_query_alt}"
- }
- }
+ reference = "%{tolower:type.%{Acct-Status-Type}.query}"
+ type {
+ accounting-on {
+ query = "${....accounting_onoff_query}"
+ }
+ accounting-off {
+ query = "${....accounting_onoff_query}"
+ }
+ start {
+ query = "${....accounting_start_query}"
+ query = "${....accounting_start_query_alt}"
+ }
+ interim-update {
+ query = "${....accounting_update_query}"
+ query = "${....accounting_update_query_alt}"
+ }
+ stop {
+ query = "${....accounting_stop_query}"
+ query = "${....accounting_stop_query_alt}"
+ }
+ }
}
post-auth {
- query = "${..postauth_query}"
+ query = "${..postauth_query}"
}
In general, it is safer to migrate the configuration rather than
trying to "patch" it, to make it look like a v2 configuration.
+Note that the sub-sections holding the queries are labelled
+``accounting-on``, and not ``accounting_on``. The reason is that the
+names of these sections are taken directly from the
+``Accounting-Request`` packet, and the ``Acct-Status-Type`` field.
+The ``sql`` module looks at the value of that field, and then looks
+for a section of that name, in order to find the query to use.
+
+That process means that the server can be extended to support any new
+value of ``Acct-Status-Type``, simply by adding a named sub-section,
+and a query. This behavior is preferable to that of v2, which had
+hard-coded queries for certain ``Acct-Status-Type`` values, and was
+ignored all other values.
+
rlm_ldap
---------
+~~~~~~~~
The LDAP module configuration has been substantially changed. Please
read ``raddb/mods-available/ldap``. It now uses a connection pool,
``post-auth`` should now set ``edir_autz = yes``, and remove the ``ldap``
module from the ``post-auth`` section.
-rlm_ldap/LDAP-Group
--------------------
+rlm_ldap and LDAP-Group
+~~~~~~~~~~~~~~~~~~~~~~~
In 2.x.x the registration of the ``LDAP-Group`` pair comparison was done
by the last instance of rlm_ldap to be instantiated. In 3.0 this has
``LDAP-Group``.
If ``<instance>-LDAP-Group`` is already used throughout your configuration
-no changes need to be made.
+no changes will be needed.
+
+rlm_ldap authentication
+~~~~~~~~~~~~~~~~~~~~~~~
+
+In 2.x.x the LDAP module had a ``set_auth_type`` configuration item,
+which forced ``Auth-Type := ldap``. This was removed in 3.x.x as it
+often did not work, and was not consistent with the rest of the
+server. We generally recommend that LDAP should be used as a
+database, and that FreeRADIUS should do authentication.
+
+The only reason to use ``Auth-Type := ldap`` is when the LDAP server
+will not supply the "known good" password to FreeRADIUS, *and* where
+the Access-Request contains User-Password. This situation happens
+only for Active Directory. If you think you need to force ``Auth-Type
+:= ldap`` in other situations, you are very likely to be wrong.
+
+The following is an example of what should be inserted into the
+``authorize {}`` and ``authenticate {}`` sections of the relevant
+virtual-servers, to get functionality equivalent to v2.x::
+
+ authorize {
+ ...
+ ldap
+ if ((ok || updated) && User-Password) {
+ update control {
+ Auth-Type := ldap
+ }
+ }
+ ...
+ }
+
+ authenticate {
+ ...
+ Auth-Type ldap {
+ ldap
+ }
+ ...
+ }
rlm_eap
--------
+~~~~~~~
The EAP configuration has been moved from ``eap.conf`` to
``mods-available/eap``. A new ``pwd`` subsection has been added for
EAP-PWD.
rlm_expiration & rlm_logintime
--------------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The rlm_expiration and rlm_logintime modules no longer add a ``Reply-Message``,
the same behaviour can be achieved checking the return code of the module and
}
rlm_unix
---------
+~~~~~~~~
-The unix module does not have an "authenticate" section. So you
-cannot set "Auth-Type := System". The "unix" module has also been
-deleted from the examples in sites-available/. Listing it there has
-been deprecated for many years.
+The ``unix`` module does not have an ``authenticate`` section. So you
+cannot set ``Auth-Type := System``. The ``unix`` module has also been
+deleted from the examples in ``sites-available/``. Listing it there
+has been deprecated for many years.
The PAP module can do crypt authentication. It should be used instead
of Unix authentication.
-The Unix module still can pull the passwords from /etc/passwd, or
-/etc/shadow. This is done by listing it in the "authorize" section,
-as is done in the sites-available/ examples.
-
-
-RadSec
-------
-
-RadSec (or RADIUS over TLS) is now supported. RADIUS over bare TCP
-is also supported, but is recommended only for secure networks.
-
-See ``sites-available/tls`` for complete details on using TLS. The server
-can both receive incoming TLS connections, and also originate outgoing
-TLS connections.
-
-The TLS configuration is taken from the old EAP-TLS configuration. It
-is largely identical to the old EAP-TLS configuration, so it should be
-simple to use and configure. It re-uses much of the EAP-TLS code,
-so it is well-tested and reliable.
+The Unix module still can pull the passwords from ``/etc/passwd``, or
+``/etc/shadow``. This is done by listing it in the ``authorize``
+section, as is done in the examples in ``sites-available/``. However,
+some systems using NIS or NSS will not supply passwords to the
+``unix`` module. For those systems, we recommend putting users and
+passwords into a database, instead of relying on ``/etc/passwd``.
-Once RadSec is enabled, normal debugging mode will not work. This is
-because the TLS code requires threading to work properly. Instead of doing::
+New Modules
+-----------
- $ radiusd -X
+rlm_date
+~~~~~~~~
-you will need to do::
+Instances of rlm_date register an xlat method which can translate
+integer and date values to an arbitrarily formatted date time
+string, or an arbitrarily formated time string to an integer,
+depending on the attribute type passed.
- $ radiusd -fxx -l stdout
+rlm_rest
+~~~~~~~~
-Sorry, but that's the price to pay for using RadSec.
+The ``rest`` module is used to translate RADIUS requests into
+RESTfull HTTP requests. Currently supported body types are JSON
+and POST.
-PAP and User-Password
----------------------
+rlm_unpack
+~~~~~~~~~~
-From version 3.0 onwards the server no longer supports authenticating
-against a cleartext password in the 'User-Password' attribute. Any
-occurences of this (for instance, in the users file) should now be changed
-to 'Cleartext-Password' instead.
+The ``unpack`` module is used to turn data buried inside of binary
+attributes. e.g. if we have ``Class = 0x00000001020304`` then::
-If this is not done, authentication will likely fail. The server will
-also print a helpful message in debugging mode.
+ Tmp-Integer-0 := "%{unpack:&Class 4 short}"
-If it really is impossible to do this, the following unlang inserted above
-the call to the pap module may be used to copy User-Password to the correct
-attribute::
+will unpack octets 4 and 5 as a "short", which has value 0x0304.
+All integers are assumed to be in network byte order.
- if (!control:Cleartext-Password && control:User-Password) {
- update control {
- Cleartext-Password := "%{control:User-Password}"
- }
- }
+rlm_yubikey
+~~~~~~~~~~~
-However, this should only be seen as a temporary, not permanent, fix.
-It is better to fix your databases to contain the correct
-configuration.
+The ``yubikey`` module can be used to forward yubikey OTP token
+values to a Yubico validation server, or decrypt the token
+using a PSK.
Deleted Modules
-===============
+---------------
The following modules have been deleted, and are no longer supported
in Version 3. If you are using one of these modules, your
the freeradius-devel list, and ask about the module.
rlm_acct_unique
----------------
+~~~~~~~~~~~~~~~
This module has been replaced by the "acct_unique" policy. See
raddb/policy.d/accounting.
for Acct-Unique-Id.
rlm_acctlog
------------
+~~~~~~~~~~~
You should use rlm_linelog instead. That module has a superset of the
acctlog functionality.
rlm_attr_rewrite
-----------------
+~~~~~~~~~~~~~~~~
The attr_rewrite module looked for an attribute, and then re-wrote it,
or created a new attribute. All of that can be done in "unlang".
We suggest updating all uses of attr_rewrite to use unlang instead.
rlm_checkval
-------------
+~~~~~~~~~~~~
The checkval module compared two attributes. All of that can be done in "unlang"::
We suggest updating all uses of checkval to use unlang instead.
rlm_dbm
--------
+~~~~~~~
No one seems to use it. There is no sample configuration for it.
There is no speed advantage to using it over the "files" module.
real database such as SQL.
rlm_fastusers
--------------
+~~~~~~~~~~~~~
No one seems to use it. It has been deprecated since Version 2.0.0.
The "files" module was rewritten so that the "fastusers" module was no
longer necessary.
rlm_policy
-----------
+~~~~~~~~~~
No one seems to use it. Almost all of its functionality is available
via "unlang".
rlm_sim_files
--------------
+~~~~~~~~~~~~~
The rlm_sim_files module has been deleted. It was never marked "stable",
and was never used in a production environment. There are better ways
files, and create attributes from them.
rlm_sql_log
------------
+~~~~~~~~~~~
This has been replaced with the "null" sql driver. See
raddb/mods-available/sql for an example configuration.
The main SQL module has more functionality than rlm_sql_log, and
results in less code in the server.
+
+Other Functionality
+-------------------
+
+The following is a list of new / changed functionality.
+
+RadSec
+~~~~~~
+
+RadSec (or RADIUS over TLS) is now supported. RADIUS over bare TCP
+is also supported, but is recommended only for secure networks.
+
+See ``sites-available/tls`` for complete details on using TLS. The server
+can both receive incoming TLS connections, and also originate outgoing
+TLS connections.
+
+The TLS configuration is taken from the old EAP-TLS configuration. It
+is largely identical to the old EAP-TLS configuration, so it should be
+simple to use and configure. It re-uses much of the EAP-TLS code,
+so it is well-tested and reliable.
+
+Once RadSec is enabled, normal debugging mode will not work. This is
+because the TLS code requires threading to work properly. Instead of doing::
+
+ $ radiusd -X
+
+you will need to do::
+
+ $ radiusd -fxx -l stdout
+
+That's the price to pay for using RadSec. This limitation may be
+lifted in a future version of the server.
+
+
+PAP and User-Password
+~~~~~~~~~~~~~~~~~~~~~
+
+From version 3.0 onwards the server no longer supports authenticating
+against a cleartext password in the 'User-Password' attribute. Any
+occurences of this (for instance, in the users file) should now be changed
+to 'Cleartext-Password' instead.
+
+e.g. change entries like this::
+
+ bob User-Password == "hello"
+
+to ones like this::
+
+ bob Cleartext-Password := "hello"
+
+
+If this is not done, authentication will likely fail. The server will
+also print a helpful message in debugging mode.
+
+If it really is impossible to do this, the following unlang inserted above
+the call to the pap module may be used to copy User-Password to the correct
+attribute::
+
+ if (!control:Cleartext-Password && control:User-Password) {
+ update control {
+ Cleartext-Password := "%{control:User-Password}"
+ }
+ }
+
+However, this should only be seen as a temporary, not permanent, fix.
+It is better to fix your databases to use the correct configuration.
+
+Unlang
+~~~~~~
+
+The unlang policy language is compatible with v2, but has a number of
+new features. See ``man unlang`` for complete documentation.
+
+ERRORS
+
+Many more errors are caught when the server is starting up. Syntax
+errors in ``unlang`` are caught, and a helpful error message is
+printed. The error message points to the exact place where the error
+occurred::
+
+ ./raddb/sites-enabled/default[230]: Parse error in condition
+ ERROR: if (User-Name ! "bob") {
+ ERROR: ^ Invalid operator
+
+``update`` sections are more generic. Instead of doing ``update
+reply``, you can do the following::
+
+ update {
+ reply:Class := 0x0000
+ control:Cleartext-Password := "hello"
+ }
+
+This change means that you need fewer ``update`` sections.
+
+COMPARISONS
+
+Attribute comparisons can be done via the ``&`` operator. When you
+needed to compare two attributes, the old comparison style was::
+
+ if (User-Name == "%{control:Tmp-String-0}") {
+
+This syntax is inefficient, as the ``Tmp-String-0`` attribute would be
+printed to an intermediate string, causing unnecessary work. You can
+now instead compare the two attributes directly::
+
+ if (&User-Name == &control:Tmp-String-0) {
+
+See ``man unlang`` for more details.
+
+CASTS
+
+Casts are now permitted. This allows you to force type-specific
+comparisons::
+
+ if (<ipaddr>"%{sql: SELECT...}" == 127.0.0.1) {
+
+This forces the string returned by the SELECT to be treated as an IP
+address, and compare to ``127.0.0.1``. Previously, the comparison
+would have been done as a simple string comparison.
+
+NETWORKS
+
+IP networks are now supported::
+
+ if (127.0.0.1/32 == 127.0.0.1) {
+
+Will be ``true``. The various comparison operators can be used to
+check IP network membership::
+
+ if (127/8 > 127.0.0.1) {
+
+Returns ``true``, because ``127.0.0.1`` is within the ``127/8``
+network. However, the following comparison will return ``false``::
+
+ if (127/8 > 192.168.0.1) {
+
+because ``192.168.0.1`` is outside of the ``127/8`` network.
+
+OPTIMIZATION
+
+As ``unlang`` is now pre-compiled, many compile-time optimizations are
+done. This means that the debug output may not be exactly the same as
+what is in the configuration files::
+
+ if (0 && (User-Name == "bob')) {
+
+The result will always be ``false``, as the ``if 0`` prevents the
+following ``&& ...`` from being evaluated.
+
+Not only that, but the entire contents of that section will be ignored
+entirely::
+
+ if (0) {
+ this_module_does_not_exist
+ and_this_one_does_not_exist_either
+ }
+
+In v2, that configuration would result in a parse error, as there is
+no module called ``this_module_does_not_exist``. In v3, that text is
+ignored. This ability allows you to have dynamic configurations where
+certain parts are used (or not) depending on compile-time configuration.
+
+Similarly, conditions which always evaluate to ``true`` will be
+optimized away::
+
+ if (1) {
+ files
+ }
+
+That configuration will never show the ``if (1)`` output in debugging mode.
+
+
+Dialup_admin
+------------
+
+The dialip_admin directory has been removed. No one stepped forward
+to maintain it, and the code had not been changed in many years.
+
# The list of files to install.
#
LOCAL_FILES := clients.conf dictionary templates.conf experimental.conf \
- proxy.conf radiusd.conf trigger.conf README.rst
+ proxy.conf radiusd.conf trigger.conf README.rst panic.gdb
DEFAULT_SITES := default inner-tunnel
LOCAL_SITES := $(addprefix raddb/sites-enabled/,$(DEFAULT_SITES))
detail detail.log digest dhcp dynamic_clients eap \
echo exec expiration expr files linelog logintime \
mschap ntlm_auth pap passwd preprocess radutmp realm \
- replicate soh sradutmp unix utf8
+ replicate soh sradutmp unix unpack utf8
LOCAL_MODULES := $(addprefix raddb/mods-enabled/,$(DEFAULT_MODULES))
# Grab files from the various subdirectories
INSTALL_FILES := $(wildcard raddb/sites-available/* raddb/mods-available/*) \
- $(addprefix raddb/,$(LOCAL_FILES)) \
- $(addprefix raddb/certs/,$(LOCAL_CERT_FILES)) \
- $(shell find raddb/mods-config -type f -print) \
- $(shell find raddb/policy.d -type f -print)
+ $(addprefix raddb/,$(LOCAL_FILES)) \
+ $(addprefix raddb/certs/,$(LOCAL_CERT_FILES)) \
+ $(shell find raddb/mods-config -type f -print) \
+ $(shell find raddb/policy.d -type f -print)
# Re-write local files to installed files, filtering out editor backups
INSTALL_RADDB := $(patsubst raddb/%,$(R)$(raddbdir)/%,\
random:
@if [ -c /dev/urandom ] ; then \
- dd if=/dev/urandom of=./random count=10 >/dev/null 2>&1; \
+ ln -sf /dev/urandom random; \
else \
date > ./random; \
fi
if [ ! -f dh ]; then
openssl dhparam -out dh 1024 || exit 1
if [ -e /dev/urandom ] ; then
- dd if=/dev/urandom of=./random count=10 >/dev/null 2>&1;
+ ln -sf /dev/urandom random
else
date > ./random;
fi
# format is still accepted.
#
client localhost {
- # Allowed values are:
- # dotted quad (1.2.3.4)
- # hostname (radius.example.com)
+ # Only *one* of ipaddr, ipv4addr, ipv6addr may be specified for
+ # a client.
+ #
+ # ipaddr will accept IPv4 or IPv6 addresses with optional CIDR
+ # notation '/<mask>' to specify ranges.
+ #
+ # ipaddr will accept domain names e.g. example.org resolving
+ # them via DNS.
+ #
+ # If both A and AAAA records are found, A records will be
+ # used in preference to AAAA.
ipaddr = 127.0.0.1
- # OR, you can use an IPv6 address, but not both
- # at the same time.
+ # Same as ipaddr but allows v4 addresses only. Requires A
+ # record for domain names.
+# ipv4addr = * # any. 127.0.0.1 == localhost
+
+ # Same as ipaddr but allows v6 addresses only. Requires AAAA
+ # record for domain names.
# ipv6addr = :: # any. ::1 == localhost
#
# domain name, or the IP address.
#
# It is accepted for compatibility with 1.x, but it is no
- # longer necessary in 2.0
+ # longer necessary in >= 2.0
#
# shortname = localhost
# coa_server = coa
#
+ # Response window for proxied packets. If non-zero,
+ # then the lower of (home, client) response_window
+ # will be used.
+ #
+ # i.e. it can be used to lower the response_window
+ # packets from one client to a home server. It cannot
+ # be used to raise the response_window.
+ #
+# response_window = 10.0
+
+ #
# Connection limiting for clients using "proto = tcp".
#
# This section is ignored for clients sending UDP traffic
}
# IPv6 Client
-#client ::1 {
+#client localhost_ipv6 {
+# ipv6addr = ::1
# secret = testing123
-# shortname = localhost
#}
-#
+
# All IPv6 Site-local clients
-#client fe80::/16 {
+#client sitelocal_ipv6 {
+# ipv6addr = fe80::/16
# secret = testing123
-# shortname = localhost
#}
-#client some.host.org {
+#client example.org {
+# ipaddr = radius.example.org
# secret = testing123
-# shortname = localhost
#}
#
# When a client request comes in, the BEST match is chosen.
# i.e. The entry from the smallest possible network.
#
-#client 192.0.2.0/24 {
+#client private-network-1 {
+# ipaddr = 192.0.2.0/24
# secret = testing123-1
-# shortname = private-network-1
-#}
-#
-#client 198.51.100.0/24 {
-# secret = testing123-2
-# shortname = private-network-2
#}
-
-#client 203.0.113.1 {
-# # secret and password are mapped through the "secrets" file.
-# secret = testing123
-# shortname = liv1
-
-# The following three fields are optional, but may be used by
-# checkrad.pl for simultaneous usage checks
-
-# nas_type = livingston
-# login = !root
-# password = someadminpas
+#client private-network-2 {
+# ipaddr = 198.51.100.0/24
+# secret = testing123-2
#}
#######################################################################
# will then accept ONLY the clients listed in this section.
#
#clients per_socket_clients {
-# client 192.0.2.4 {
+# client socket_client {
+# ipaddr = 192.0.2.4
# secret = testing123
# }
#}
#
-# This is the master dictionary file, which references the
-# pre-defined dictionary files included with the server.
+# This is the local dictionary file which can be
+# edited by local administrators. It will be loaded
+# AFTER the main dictionary files are loaded.
#
-# Any new/changed attributes MUST be placed in this file, as
-# the pre-defined dictionaries SHOULD NOT be edited.
+# As of version 3.0.2, FreeRADIUS will automatically
+# load the main dictionary files from
+#
+# ${prefix}/share/freeradius/dictionary
+#
+# It is no longer necessary for this file to $INCLUDE
+# the main dictionaries. However, if the $INCLUDE
+# line is here, nothing bad will happen.
+#
+# Any new/changed attributes MUST be placed in this file.
+# The pre-defined dictionaries SHOULD NOT be edited.
#
# See "man dictionary" for documentation on its format.
#
#
#
-# The filename given here should be an absolute path.
-#
-$INCLUDE @prefix@/share/freeradius/dictionary
-
+# All local attributes and $INCLUDE's should go into
+# this file.
#
-# All additional attributes an $INCLUDE's should go into
-# a file "dictionary.local".
# If you want to add entries to the dictionary file,
# which are NOT going to be placed in a RADIUS packet,
#
#
-# These attributes are examples. Don't edit them here.
-# Instead, create a "dictionary.local" file, and place
-# them there.
+# These attributes are examples
#
#ATTRIBUTE My-Local-String 3000 string
#ATTRIBUTE My-Local-IPAddr 3001 ipaddr
#ATTRIBUTE My-Local-Integer 3002 integer
-
-#
-# Include dictionary.local, IF it exists. Otherwise, ignore it.
-#
-# This file WILL NOT EVER be created, edited, or modified
-# by FreeRADIUS.
-#
-$INCLUDE- dictionary.local
# $Id$
#
-# The "always" module is here for debugging purposes. Each
-# instance simply returns the same result, always, without
-# doing anything.
-always fail {
- rcode = fail
-}
+# The "always" module is here for debugging purposes, or
+# for use in complex policies.
+# Instance simply returns the same result, always, without
+# doing anything.
+#
+# rcode may be one of the following values:
+# - reject - Reject the user.
+# - fail - Simulate or indicate a failure.
+# - ok - Simulate or indicate a success.
+# - handled - Indicate that the request has been handled,
+# stop processing, and send response if set.
+# - invalid - Indicate that the request is invalid.
+# - userlock - Indicate that the user account has been
+# locked out.
+# - notfound - Indicate that a user account can't be found.
+# - noop - Simulate a no-op.
+# - updated - Indicate that the request has been updated.
+#
+# If an instance is listed in a session {} section,
+# this simulates a user having <integer> sessions.
+#
+# simulcount = <integer>
+#
+# If an instance is listed in a session {} section,
+# this simulates the user having multilink
+# sessions.
+#
+# mpp = <integer>
+#
always reject {
rcode = reject
}
-always noop {
- rcode = noop
+always fail {
+ rcode = fail
+}
+always ok {
+ rcode = ok
}
always handled {
rcode = handled
}
-always updated {
- rcode = updated
+always invalid {
+ rcode = invalid
+}
+always userlock {
+ rcode = userlock
}
always notfound {
rcode = notfound
}
-always ok {
- rcode = ok
- simulcount = 0
- mpp = no
+always noop {
+ rcode = noop
+}
+always updated {
+ rcode = updated
}
# proxied servers, to make sure we send back to our RADIUS client
# only allowed attributes.
attr_filter attr_filter.post-proxy {
+ key = "%{Realm}"
filename = ${modconfdir}/${.:name}/post-proxy
}
# attr_filter - filters the attributes in the packets we send to
# the RADIUS home servers.
attr_filter attr_filter.pre-proxy {
+ key = "%{Realm}"
filename = ${modconfdir}/${.:name}/pre-proxy
}
--- /dev/null
+couchbase {
+ #
+ # List of Couchbase hosts (hosts may be space, tab, comma or semi-colon separated).
+ # Ports are optional if servers are listening on the standard port.
+ # Complete pool urls are preferred.
+ #
+ server = "http://cb01.blargs.com:8091/pools/ http://cb04.blargs.com:8091/pools/"
+
+ # Couchbase bucket name
+ bucket = "radius"
+
+ # Couchbase bucket password (optional)
+ #password = "password"
+
+ # Couchbase accounting document key (unlang supported)
+ acct_key = "radacct_%{%{Acct-Unique-Session-Id}:-%{Acct-Session-Id}}"
+
+ # Value for the 'docType' element in the json body for accounting documents
+ doctype = "radacct"
+
+ ## Accounting document expire time in seconds (0 = never)
+ expire = 2592000
+
+ #
+ # Map attribute names to json element names for accounting.
+ #
+ # Configuration items are in the format:
+ # <element name> = '<radius attribute>'
+ #
+ # Attribute names should be single quoted.
+ #
+ # Note: Atrributes not in this map will not be recorded.
+ #
+ map {
+ sessionId = 'Acct-Session-Id'
+ uniqueId = 'Acct-Unique-Session-Id'
+ lastStatus = 'Acct-Status-Type'
+ authentic = 'Acct-Authentic'
+ userName = 'User-Name'
+ strippedUserName = 'Stripped-User-Name'
+ strippedUserDomain = 'Stripped-User-Domain'
+ realm = 'Realm'
+ nasIpAddress = 'NAS-IP-Address'
+ nasIdentifier = 'NAS-Identifier'
+ nasPort = 'NAS-Port'
+ calledStationId = 'Called-Station-Id'
+ calledStationSSID = 'Called-Station-SSID'
+ callingStationId = 'Calling-Station-Id'
+ framedIpAddress = 'Framed-IP-Address'
+ nasPortType = 'NAS-Port-Type'
+ connectInfo = 'Connect-Info'
+ sessionTime = 'Acct-Session-Time'
+ inputPackets = 'Acct-Input-Packets'
+ outputPackets = 'Acct-Output-Packets'
+ inputOctets = 'Acct-Input-Octets'
+ outputOctets = 'Acct-Output-Octets'
+ inputGigawords = 'Acct-Input-Gigawords'
+ outputGigawords = 'Acct-Output-Gigawords'
+ lastUpdated = 'Event-Timestamp'
+ }
+
+ # Couchbase document key for user documents (unlang supported)
+ user_key = "raduser_%{md5:%{tolower:%{%{Stripped-User-Name}:-%{User-Name}}}}"
+
+ #
+ # The connection pool is new for 3.0, and will be used in many
+ # modules, for all kinds of connection-related activity.
+ #
+ pool {
+ # Number of connections to start
+ start = ${thread[pool].start_servers}
+
+ # Minimum number of connections to keep open
+ min = ${thread[pool].min_spare_servers}
+
+ # Maximum number of connections
+ #
+ # If these connections are all in use and a new one
+ # is requested, the request will NOT get a connection.
+ #
+ # NOTE: This should be greater than or equal to "min" above.
+ max = ${thread[pool].max_servers}
+
+ # Spare connections to be left idle
+ #
+ # NOTE: Idle connections WILL be closed if "idle_timeout"
+ # is set. This should be less than or equal to "max" above.
+ spare = ${thread[pool].max_spare_servers}
+
+ # Number of uses before the connection is closed
+ #
+ # NOTE: A setting of 0 means infinite (no limit).
+ uses = 0
+
+ # The lifetime (in seconds) of the connection
+ #
+ # NOTE: A setting of 0 means infinite (no limit).
+ lifetime = 0
+
+ # The idle timeout (in seconds). A connection which is
+ # unused for this length of time will be closed.
+ #
+ # NOTE: A setting of 0 means infinite (no timeout).
+ idle_timeout = 1200
+
+ # NOTE: All configuration settings are enforced. If a
+ # connection is closed because of "idle_timeout",
+ # "uses", or "lifetime", then the total number of
+ # connections MAY fall below "min". When that
+ # happens, it will open a new connection. It will
+ # also log a WARNING message.
+ #
+ # The solution is to either lower the "min" connections,
+ # or increase lifetime/idle_timeout.
+ }
+}
# The user that the server runs as must be in the specified
# system group otherwise this will fail to work.
#
-# group = freerad
+# group = ${security.group}
#
# Every entry in the detail file has a header which
# Client's MAC address is mapped to Calling-Station-Id in policy.conf
pool_key = "%{Calling-Station-Id}"
- # For now, it only works with MySQL.
+ # For now, it works with MySQL.
$INCLUDE ${modconfdir}/sql/ippool-dhcp/mysql/queries.conf
+ # It may also work with sqlite - this is very experimental.
+ # Comment out the above line and add the following include.
+ # To use sqlite you need to add '%' to safe_characters in
+ # raddb/mods-config/sql/main/sqlite/queries.conf.
+ # $INCLUDE ${modconfdir}/sql/ippool-dhcp/sqlite/queries.conf
+
sqlippool_log_exists = "DHCP: Existing IP: %{reply:Framed-IP-Address} (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})"
sqlippool_log_success = "DHCP: Allocated IP: %{reply:Framed-IP-Address} from %{control:Pool-Name} (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} user %{User-Name})"
#
# Help prevent DoS attacks by limiting the number of
- # sessions that the server is tracking. Most systems
- # can handle ~30 EAP sessions/s, so the default limit
- # of 4096 should be OK.
- max_sessions = 4096
+ # sessions that the server is tracking. For simplicity,
+ # this is taken from the "max_requests" directive in
+ # radiusd.conf.
+ max_sessions = ${max_requests}
# Supported EAP-types
# Livingston-style 'users' file
#
+# See "man users" for more information.
+#
files {
# Search for files in a subdirectory of mods-config which
# matches this instance of the files module.
# The default key attribute to use for matches. The content
# of this attribute is used to match the "name" of the
# entry.
- #key = "%{Stripped-User-Name:-%{User-Name}}"
+ #key = "%{%{Stripped-User-Name}:-%{User-Name}}"
- # Sets a common file for all sections which do not have
- # specific files configured. It's recommended that
- # per section instances of 'files' are used, as per section
- # files will be deprecated in a future release.
+ # The old "users" style file is now located here.
filename = ${moddir}/authorize
+ # This is accepted for backwards compatibility
+ # It will be removed in a future release.
usersfile = ${moddir}/authorize
+
+ # These are accepted for backwards compatibility.
+ # They will be renamed in a future release.
acctusersfile = ${moddir}/accounting
preproxy_usersfile = ${moddir}/pre-proxy
-
- # If you want to use the old Cistron 'users' file
- # with FreeRADIUS, you should change the next line
- # to 'compat = cistron'. You can the copy your 'users'
- # file from Cistron.
- compat = no
}
#
# Allow use of unassigned Unicode code points.
#
- allow_unassigned = no
+ allow_unassigned = no
#
# Prohibit underscores and other invalid characters in domain
# DEFAULT Group == teachers, Pool-Name := "teachers"
# DEFAULT Group == other, Pool-Name := "DEFAULT"
#
-# ********* IF YOU CHANGE THE RANGE PARAMETERS YOU MUST *********
-# ********* THEN ERASE THE DB FILES *********
+# Note: If you change the range parameters you must then erase the
+# db files.
#
ippool main_pool {
+ # The main db file used to allocate addresses.
+ filename = ${db_dir}/db.ippool
- # range-start,range-stop:
- # The start and end ip addresses for this pool.
+ # The start and end ip addresses for this pool.
range_start = 192.0.2.1
range_stop = 192.0.2.254
- # netmask:
- # The network mask used for this pool.
+ # The network mask used for this pool.
netmask = 255.255.255.0
- # cache_size:
- # The gdbm cache size for the db files. Should
- # be equal to the number of ip's available in
- # the ip pool
+ # The gdbm cache size for the db files. Should
+ # be equal to the number of ip's available in
+ # the ip pool
cache_size = 800
- # session-db:
- # The main db file used to allocate addresses.
- session_db = ${db_dir}/db.ippool
-
- # ip-index:
- # Helper db index file used in multilink
+ # Helper db index file used in multilink
ip_index = ${db_dir}/db.ipindex
- # override:
- # If set, the Framed-IP-Address already in the
- # reply (if any) will be discarded, and replaced
- # with a Framed-IP-Address assigned here.
+ # If set, the Framed-IP-Address already in the
+ # reply (if any) will be discarded, and replaced
+ # ith a Framed-IP-Address assigned here.
override = no
- # maximum-timeout:
- # Specifies the maximum time in seconds that an
- # entry may be active. If set to zero, means
- # "no timeout". The default value is 0
+ # Specifies the maximum time in seconds that an
+ # entry may be active. If set to zero, means
+ # "no timeout". The default value is 0
maximum_timeout = 0
- # key:
- # The key to use for the session database (which
- # holds the allocated ip's) normally it should
- # just be the nas ip/port (which is the default).
+ # The key to use for the session database (which
+ # holds the allocated ip's) normally it should
+ # just be the nas ip/port (which is the default).
#
- # If your NAS sends the same value of NAS-Port
- # all requests, the key should be based on some
- # other attribute that is in ALL requests, AND
- # is unique to each machine needing an IP address.
- #key = "%{NAS-IP-Address} %{NAS-Port}"
+ # If your NAS sends the same value of NAS-Port
+ # all requests, the key should be based on some
+ # other attribute that is in ALL requests, AND
+ # is unique to each machine needing an IP address.
+# key = "%{NAS-IP-Address} %{NAS-Port}"
}
#
# The context pool is only used if the underlying libkrb5 reported
# that it was thread safe at compile time.
+ #
pool {
- # Number of contexts to create
- start = 10
+ # Number of connections to start
+ start = ${thread[pool].start_servers}
- # Minimum number of contexts to keep available
- min = 4
+ # Minimum number of connections to keep open
+ min = ${thread[pool].min_spare_servers}
- # Maximum number of contexts
+ # Maximum number of connections
#
- # If these contexts are all in use and a new one
+ # If these connections are all in use and a new one
# is requested, the request will NOT get a connection.
- max = 10
+ #
+ # NOTE: This should be greater than or equal to "min" above.
+ max = ${thread[pool].max_servers}
- # Spare contexts to be left idle
+ # Spare connections to be left idle
#
- # NOTE: Idle contexts WILL be closed if "idle_timeout"
- # is set.
- spare = 3
+ # NOTE: Idle connections WILL be closed if "idle_timeout"
+ # is set. This should be less than or equal to "max" above.
+ spare = ${thread[pool].max_spare_servers}
- # Number of uses before the context is freed
- # 0 means "infinite"
+ # Number of uses before the connection is closed
+ #
+ # NOTE: A setting of 0 means infinite (no limit).
uses = 0
- # The lifetime (in seconds) of the context
+ # The lifetime (in seconds) of the connection
+ #
+ # NOTE: A setting of 0 means infinite (no limit).
lifetime = 0
- # idle timeout (in seconds). A context which is
- # unused for this length of time will be freed.
- idle_timeout = 60
+ # The idle timeout (in seconds). A connection which is
+ # unused for this length of time will be closed.
+ #
+ # NOTE: A setting of 0 means infinite (no timeout).
+ idle_timeout = 0
# NOTE: All configuration settings are enforced. If a
- # context is closed because of "idle_timeout",
+ # connection is closed because of "idle_timeout",
# "uses", or "lifetime", then the total number of
- # contexts MAY fall below "min". When that
- # happens, it will create a new context. It will
+ # connections MAY fall below "min". When that
+ # happens, it will open a new connection. It will
# also log a WARNING message.
#
- # The solution is to either lower the "min" contexts,
+ # The solution is to either lower the "min" connections,
# or increase lifetime/idle_timeout.
}
}
# $Id$
#
-# Lightweight Directory Access Protocol (LDAP)
+# Lightweight Directory Access Protocol (LDAP)
#
ldap {
- #
- # Note that this needs to match the name in the LDAP
- # server certificate, if you're using ldaps.
- #
- # The ldap client libraries can do fail-over from one
- # server to another. Enable this by specifying
- # multiple host names, separated by commas.
- #
- # e.g. server = "ldap1.example.org,ldap2.example.org"
- #
- # Otherwise, it will use just one server.
- server = "ldap.example.org"
+ # Note that this needs to match the name(s) in the LDAP server
+ # certificate, if you're using ldaps. See OpenLDAP documentation
+ # for the behavioral semantics of specifying more than one host.
+ server = "ldap.rrdns.example.org ldap.rrdns.example.org ldap.example.org"
- # Port to connect on, defaults to 389. Setting this to
- # 636 will enable LDAPS if start_tls (see below) is not
- # able to be used.
+ # Port to connect on, defaults to 389. Setting this to 636 will enable
+ # LDAPS if start_tls (see below) is not able to be used.
# port = 389
- # Administrator account for searching and possibly modifying.
+ # Administrator account for searching and possibly modifying.
# identity = "cn=admin,dc=example,dc=org"
# password = mypass
# base_dn = "dc=example,dc=org"
#
+ # Generic valuepair attribute
+ #
+
+ # If set, this will attribute will be retrieved in addition to any
+ # mapped attributes.
+ #
+ # Values should be in the format:
+ # <radius attr> <op> <value>
+ #
+ # Where:
+ # <radius attr>: Is the attribute you wish to create
+ # with any valid list and request qualifiers.
+ # <op>: Is any assignment attribute (=, :=, +=, -=).
+ # <value>: Is the value to parse into the new valuepair.
+ # If the attribute name is wrapped in double
+ # quotes it will be xlat expanded.
+# valuepair_attribute = "radiusAttribute"
+
+ #
# Mapping of LDAP directory attributes to RADIUS dictionary attributes.
#
+
# WARNING: Although this format is almost identical to the unlang
# update section format, it does *NOT* mean that you can use other
# unlang constructs in module configuration files.
# Note: LDAP attribute names should be single quoted unless you want
# the name value to be derived from an xlat expansion, or an
# attribute ref.
- #
update {
control:Password-With-Header += 'userPassword'
# control:NT-Password := 'ntPassword'
# reply:Tunnel-Type := 'radiusTunnelType'
# reply:Tunnel-Medium-Type := 'radiusTunnelMediumType'
# reply:Tunnel-Private-Group-ID := 'radiusTunnelPrivategroupId'
- }
- #
- # Generic valuepair attribute
- # If set, this will attribute will be retrieved in addition to any
- # mapped attributes.
- #
- # Values should be in the format:
- # <radius attr> <op> <value>
- #
- # Where:
- # <radius attr>: Is the attribute you wish to create
- # with any valid list and request qualifiers.
- # <op>: Is any assignment attribute (=, :=, +=, -=).
- # <value>: Is the value to parse into the new valuepair.
- # If the attribute name is wrapped in double
- # quotes it will be xlat expanded.
- #
-# valuepair_attribute = "radiusAttribute"
+ # These are provided for backwards compatibility.
+ # Where only a list is specified as the RADIUS attribute,
+ # the value of the LDAP attribute is parsed as a valuepair
+ # in the same format as the 'valuepair_attribute' (above).
+# control: += 'radiusCheckAttributes'
+# reply: += 'radiusReplyAttributes'
+ }
- # Set to yes if you have eDirectory and want to use the universal
- # password mechanism.
+ # Set to yes if you have eDirectory and want to use the universal
+ # password mechanism.
# edir = no
- # Set to yes if you want to bind as the user after retrieving the
- # Cleartext-Password. This will consume the login grace, and
- # verify user authorization.
+ # Set to yes if you want to bind as the user after retrieving the
+ # Cleartext-Password. This will consume the login grace, and
+ # verify user authorization.
# edir_autz = no
+ # Note: set_auth_type was removed in v3.x.x
+ # Equivalent functionality can be achieved by adding the following
+ # stanza to the authorize {} section of your virtual server.
+ #
+ # ldap
+ # if ((ok || updated) && User-Password) {
+ # update {
+ # control:Auth-Type := ldap
+ # }
+ # }
+
#
# User object identification.
#
user {
- # Where to start searching in the tree for users
+ # Where to start searching in the tree for users
base_dn = "${..base_dn}"
# Filter for user objects, should be specific enough
# to identify a single user object.
filter = "(uid=%{%{Stripped-User-Name}:-%{User-Name}})"
- # Search scope, may be 'base', 'one', sub' or 'children'
+ # Search scope, may be 'base', 'one', sub' or 'children'
# scope = 'sub'
# If this is undefined, anyone is authorised.
# User membership checking.
#
group {
- # Where to start searching in the tree for groups
+ # Where to start searching in the tree for groups
base_dn = "${..base_dn}"
# Filter for group objects, should match all available
#
# This feature is intended to be used with rlm_cache.
#
- # If you with to use this feature, you should enable
+ # If you wish to use this feature, you should enable
# the type that matches the format of your check items
# i.e. if your groups are specified as DNs then enable
# cacheable_dn else enable cacheable_name.
# cacheable_name = "no"
# cacheable_dn = "no"
+
+ # Override the normal cache attribute (<inst>-LDAP-Group)
+ # and create a custom attribute. This can help if multiple
+ # module instances are used in fail-over.
+# cache_attribute = "LDAP-Cached-Membership"
}
#
# Arbitrary attributes (accessible by %{client:<attr>}) are not yet supported.
#
# The following attributes are required:
- # * identifier - IPv4 address, or IPv4 address with prefix, or hostname)
- # * secret - RADIUS shared secret
+ # * identifier - IPv4 address, or IPv4 address with prefix, or hostname.
+ # * secret - RADIUS shared secret.
#
# The following attributes are optional:
# * shortname - Friendly name associated with the client
# Schemas are available in doc/schemas/ldap for openldap and eDirectory
#
attribute {
- identifier = 'radiusClientIdentifier'
- secret = 'radiusClientSecret'
-# shortname = 'radiusClientShortname'
-# nas_type = 'radiusClientType'
-# virtual_server = 'radiusClientVirtualServer'
-# require_message_authenticator = 'radiusClientRequireMa'
+ identifier = 'radiusClientIdentifier'
+ secret = 'radiusClientSecret'
+# shortname = 'radiusClientShortname'
+# nas_type = 'radiusClientType'
+# virtual_server = 'radiusClientVirtualServer'
+# require_message_authenticator = 'radiusClientRequireMa'
}
}
- #
# Load clients on startup
- #
# read_clients = no
#
# Modify user object on receiving Accounting-Request
#
+
# Useful for recording things like the last time the user logged
# in, or the Acct-Session-ID for CoA/DM.
#
# WARNING: If using the ':=' operator with a multi-valued LDAP
# attribute, all instances of the attribute will be removed and
# replaced with a single attribute.
- #
accounting {
reference = "%{tolower:type.%{Acct-Status-Type}}"
}
}
+ #
# LDAP connection-specific options.
#
# These options set timeouts, keep-alives, etc. for the connections.
chase_referrals = yes
rebind = yes
- # seconds to wait for LDAP query to finish. default: 20
+ # Seconds to wait for LDAP query to finish. default: 20
timeout = 10
- # seconds LDAP server has to process the query (server-side
+ # Seconds LDAP server has to process the query (server-side
# time limit). default: 20
#
# LDAP_OPT_TIMELIMIT is set to this value.
timelimit = 3
- #
- # seconds to wait for response of the server. (network
- # failures) default: 10
+ # Seconds to wait for response of the server. (network
+ # failures) default: 10
#
# LDAP_OPT_NETWORK_TIMEOUT is set to this value.
net_timeout = 1
- # LDAP_OPT_X_KEEPALIVE_IDLE
+ # LDAP_OPT_X_KEEPALIVE_IDLE
idle = 60
- # LDAP_OPT_X_KEEPALIVE_PROBES
+ # LDAP_OPT_X_KEEPALIVE_PROBES
probes = 3
- # LDAP_OPT_X_KEEPALIVE_INTERVAL
+ # LDAP_OPT_X_KEEPALIVE_INTERVAL
interval = 3
# ldap_debug: debug flag for LDAP SDK
# The connection pool is new for 3.0, and will be used in many
# modules, for all kinds of connection-related activity.
#
+ # When the server is not threaded, the connection pool
+ # limits are ignored, and only one connection is used.
pool {
- # Number of connections to start
+ # Number of connections to start
start = 5
- # Minimum number of connections to keep open
+ # Minimum number of connections to keep open
min = 4
- # Maximum number of connections
+ # Maximum number of connections
#
- # If these connections are all in use and a new one
- # is requested, the request will NOT get a connection.
- max = 10
+ # If these connections are all in use and a new one
+ # is requested, the request will NOT get a connection.
+ #
+ # Setting 'max' to LESS than the number of threads means
+ # that some threads may starve, and you will see errors
+ # like "No connections available and at max connection limit"
+ #
+ # Setting 'max' to MORE than the number of threads means
+ # that there are more connections than necessary.
+ max = ${thread[pool].max_servers}
- # Spare connections to be left idle
+ # Spare connections to be left idle
#
- # NOTE: Idle connections WILL be closed if "idle_timeout"
- # is set.
+ # NOTE: Idle connections WILL be closed if "idle_timeout"
+ # is set.
spare = 3
- # Number of uses before the connection is closed
+ # Number of uses before the connection is closed
#
- # 0 means "infinite"
+ # 0 means "infinite"
uses = 0
- # The lifetime (in seconds) of the connection
+ # The lifetime (in seconds) of the connection
lifetime = 0
- # idle timeout (in seconds). A connection which is
- # unused for this length of time will be closed.
+ # Idle timeout (in seconds). A connection which is
+ # unused for this length of time will be closed.
idle_timeout = 60
- # NOTE: All configuration settings are enforced. If a
- # connection is closed because of "idle_timeout",
- # "uses", or "lifetime", then the total number of
- # connections MAY fall below "min". When that
- # happens, it will open a new connection. It will
- # also log a WARNING message.
+ # NOTE: All configuration settings are enforced. If a
+ # connection is closed because of "idle_timeout",
+ # "uses", or "lifetime", then the total number of
+ # connections MAY fall below "min". When that
+ # happens, it will open a new connection. It will
+ # also log a WARNING message.
#
- # The solution is to either lower the "min" connections,
- # or increase lifetime/idle_timeout.
+ # The solution is to either lower the "min" connections,
+ # or increase lifetime/idle_timeout.
}
-
}
permissions = 0600
#
- # The Unix group of the log file.
+ # The Unix group which owns the log file.
#
# The user that freeradius runs as must be in the specified
# group, otherwise it will not be possible to set the group.
#
- # group = freerad
+ # group = ${security.group}
#
# If logging via syslog, the facility can be set here. Otherwise
#
# Reference the Packet-Type (Access-Request, etc.) If it doesn't
# exist, reference the "format" entry, above.
- reference = "%{%{Packet-Type}:-format}"
+ reference = "messages.%{%{Packet-Type}:-default}"
#
- # Followed by a series of log messages.
- Access-Request = "Requested access: %{User-Name}"
- Access-Reject = "Rejected access: %{User-Name}"
- Access-Challenge = "Sent challenge: %{User-Name}"
+ # The messages defined here are taken from the "reference"
+ # expansion, above.
+ #
+ messages {
+ default = "Unknown packet type %{Packet-Type}"
+
+ Access-Request = "Requested access: %{User-Name}"
+ Access-Reject = "Rejected access: %{User-Name}"
+ Access-Challenge = "Sent challenge: %{User-Name}"
+ }
+}
+#
+# Another example, for accounting packets.
+#
+linelog log_accounting {
#
- # The log messages can be grouped into sections and
- # sub-sections, too. The "reference" item needs to have a "."
- # for every section. e.g. reference = foo.bar will reference
- # the "foo" section, "bar" configuration item.
+ # Used if the expansion of "reference" fails.
#
+ format = ""
- #
- # Used if: reference = "foo.bar".
- foo {
- bar = "Example log. Please ignore"
- }
+ filename = ${logdir}/linelog-accounting
+
+ permissions = 0600
+
+ reference = "Accounting-Request.%{%{Acct-Status-Type}:-unknown}"
#
# Another example:
- # reference = "Accounting-Request.%{%{Acct-Status-Type}:-unknown}"
+ #
#
Accounting-Request {
Start = "Connect: [%{User-Name}] (did %{Called-Station-Id} cli %{Calling-Station-Id} port %{NAS-Port} ip %{Framed-IP-Address})"
Accounting-Off = "NAS %{Packet-Src-IP-Address} (%{NAS-IP-Address}) just went offline"
# don't log anything for other Acct-Status-Types.
- unknown = ""
+ unknown = "NAS %{Packet-Src-IP-Address} (%{NAS-IP-Address}) sent unknown Acct-Status-Type %{Acct-Status-Type}"
}
-
}
#
# http://www.openldap.org/faq/data/cache/347.html
pap {
- # The "auto_header" configuration item can be set to "yes".
- # In this case, the module will look inside of the User-Password
- # attribute for the headers {crypt}, {clear}, etc., and will
- # automatically create the attribute on the right-hand side,
- # with the correct value.
- auto_header = no
-
# By default the server will use heuristics to try and automatically
# handle base64 or hex encoded passwords. This behaviour can be
# stopped by setting the following to "no".
# An example configuration for using /etc/passwd.
#
-# We do NOT recommend using the configuration below. See the "unix"
-# module, or the "pam" module for a cleaner way to get system passwords.
-# Using this configuration means that the server will find *only* those
-# passwords which are in /etc/passwd, and will *ignore* all of the
-# passwords in NIS, LDAP, etc.
+# This is an example which will NOT WORK if you have shadow passwords,
+# NIS, etc. The "unix" module is normally responsible for reading
+# system passwords. You should use it instead of this example.
#
passwd etc_passwd {
filename = /etc/passwd
# %RAD_CHECK Check items
# %RAD_REQUEST Attributes from the request
# %RAD_REPLY Attributes for the reply
+ # %RAD_REQUEST_PROXY Attributes from the proxied request
+ # %RAD_REQUEST_PROXY_REPLY Attributes from the proxy reply
+ #
+ # The interface between FreeRADIUS and Perl is strings.
+ # That is, attributes of type "octets" are converted to
+ # printable strings, such as "0xabcdef". If you want to
+ # access the binary values of the attributes, you should
+ # call the Perl "pack" function. Then to send any binary
+ # data back to FreeRADIUS, call the Perl "unpack" function,
+ # so that the contents of the hashes are printable strings.
+ #
+ # IP addresses are sent as strings, e.g. "192.0.2.25", and
+ # not as a 4-byte binary value. The same applies to other
+ # attribute data types.
+ #
+ # Attributes of type "string" are copied to Perl as-is.
+ # They are not escaped or interpreted.
#
# The return codes from functions in the perl_script
# are passed directly back to the server. These
- # codes are defined in doc/configurable_failover,
- # src/include/modules.h (RLM_MODULE_REJECT, etc),
- # and are pre-defined in the 'example.pl' program
- # which is included.
+ # codes are defined in mods-config/example.pl
#
+ # You can define configuration items (and nested sub-sections) in perl "config" section.
+ # These items will be accessible in the perl script through %RAD_PERLCONF hash.
+ # For instance: $RAD_PERLCONF{'name'} $RAD_PERLCONF{'sub-config'}->{'name'}
+ #
+ #config {
+ # name = "value"
+ # sub-config {
+ # name = "value of name from config.sub-config"
+ # }
+ #}
+
#
# List of functions in the module to call.
# Uncomment and change if you want to use function
# characters, so that will limit the possible choices
# of keys.
#
- # You may want instead: %{Stripped-User-Name:-%{User-Name}}
+ # You may want instead: %{%{Stripped-User-Name}:-%{User-Name}}
username = %{User-Name}
# connection pool.
#
pool {
- # start this many connections
- start = 1
+ # Number of connections to start
+ start = ${thread[pool].start_servers}
- # Keep at least "min" connections open
- min = 1
+ # Minimum number of connections to keep open
+ min = ${thread[pool].min_spare_servers}
- # No more than "max" connections at any one time
- max = 10
+ # Maximum number of connections
+ #
+ # If these connections are all in use and a new one
+ # is requested, the request will NOT get a connection.
+ #
+ # NOTE: This should be greater than or equal to "min" above.
+ max = ${thread[pool].max_servers}
- # try to keep "spare" connections
- spare = 0
+ # Spare connections to be left idle
+ #
+ # NOTE: Idle connections WILL be closed if "idle_timeout"
+ # is set. This should be less than or equal to "max" above.
+ spare = ${thread[pool].max_spare_servers}
- # If we have spare connections for "cleanup_delay" seconds,
- # start deleting them
- cleanup_delay = 300
+ # Number of uses before the connection is closed
+ #
+ # NOTE: A setting of 0 means infinite (no limit).
+ uses = 0
- # connections last no more than "lifetime" seconds.
+ # The lifetime (in seconds) of the connection
+ #
+ # NOTE: A setting of 0 means infinite (no limit).
lifetime = 86400
- # close idle connections are "idle_timeout" seconds
+ # The pool is checked for free connections every
+ # "cleanup_interval". If there are free connections,
+ # then one of them is closed.
+ cleanup_interval = 300
+
+ # The idle timeout (in seconds). A connection which is
+ # unused for this length of time will be closed.
+ #
+ # NOTE: A setting of 0 means infinite (no timeout).
idle_timeout = 600
- # allow no more than "uses" queries through a connection.
- # after that, close it and open a new one.
- uses = 0
+ # NOTE: All configuration settings are enforced. If a
+ # connection is closed because of "idle_timeout",
+ # "uses", or "lifetime", then the total number of
+ # connections MAY fall below "min". When that
+ # happens, it will open a new connection. It will
+ # also log a WARNING message.
+ #
+ # The solution is to either lower the "min" connections,
+ # or increase lifetime/idle_timeout.
}
}
# comment out the configuration item below.
connect_uri = "http://127.0.0.1/"
+ #
+ # The following config items can be used in each of the sections.
+ # The sections themselves reflect the sections in the server.
+ # For example if you list rest in the authorize section of a virtual server,
+ # the settings from the authorize section here will be used.
+ #
+ # The following config items may be listed in any of the sections:
+ # uri - to send the request to.
+ # method - HTTP method to use, one of 'get', 'post', 'put', 'delete'.
+ # body - The format of the HTTP body sent to the remote server.
+ # May be 'none', 'post' or 'json', defaults to 'none'.
+ # tls - TLS settings for HTTPS.
+ # auth - HTTP auth method to use, one of 'none', 'srp', 'basic',
+ # 'digest', 'digest-ie', 'gss-negotiate', 'ntlm',
+ # 'ntlm-winbind', 'any', 'safe'. defaults to 'none'.
+ # username - User to authenticate as, will be expanded.
+ # password - Password to use for authentication, will be expanded.
+ # require_auth - Require HTTP authentication.
+ # timeout - HTTP request timeout in seconds, defaults to 4.
+ #
authorize {
uri = "${..connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?section=authorize"
method = "get"
#
pool {
# Number of connections to start
- start = 5
+ start = ${thread[pool].start_servers}
# Minimum number of connections to keep open
- min = 4
+ min = ${thread[pool].min_spare_servers}
# Maximum number of connections
#
# If these connections are all in use and a new one
# is requested, the request will NOT get a connection.
- max = 10
+ #
+ # NOTE: This should be greater than or equal to "min" above.
+ max = ${thread[pool].max_servers}
# Spare connections to be left idle
#
# NOTE: Idle connections WILL be closed if "idle_timeout"
- # is set.
- spare = 3
+ # is set. This should be less than or equal to "max" above.
+ spare = ${thread[pool].max_spare_servers}
# Number of uses before the connection is closed
#
- # 0 means "infinite"
+ # NOTE: A setting of 0 means infinite (no limit).
uses = 0
# The lifetime (in seconds) of the connection
+ #
+ # NOTE: A setting of 0 means infinite (no limit).
lifetime = 0
- # idle timeout (in seconds). A connection which is
+ # The idle timeout (in seconds). A connection which is
# unused for this length of time will be closed.
+ #
+ # NOTE: A setting of 0 means infinite (no timeout).
idle_timeout = 60
# NOTE: All configuration settings are enforced. If a
#
#
-#
-# Several drivers accept specific options, to set them a config section
-# matching the name of the driver should be added to the sql instance.
-#
-# Driver specific options are:
-#
-# sqlite {
-# # Path to the sqlite database
-# filename = "/my/sqlite/database.db"
-#
-# # If the file above does not exist and bootstrap is set
-# # a new database file will be created, and the SQL statements
-# # contained within the file will be executed.
-# bootstrap = "/my/sqlite/schema.sql"
-# }
-#
-# mysql {
-# # If any of the below files are set tls encryption is enabled
-# tls {
-# ca_file = "/etc/ssl/certs/my_ca.crt"
-# ca_path = "/etc/ssl/certs/"
-# certificate_file = "/etc/ssl/certs/private/client.crt"
-# private_key_file = "/etc/ssl/certs/private/client.key"
-# cipher = "DHE-RSA-AES256-SHA:AES128-SHA"
-# }
-# }
-
sql {
# The sub-module to use to execute queries. This should match
# the database you're attempting to connect to.
#
driver = "rlm_sql_null"
+#
+# Several drivers accept specific options, to set them, a
+# config section with the the name as the driver should be added
+# to the sql instance.
+#
+# Driver specific options are:
+#
+# sqlite {
+# # Path to the sqlite database
+# filename = "/my/sqlite/database.db"
+#
+# # If the file above does not exist and bootstrap is set
+# # a new database file will be created, and the SQL statements
+# # contained within the file will be executed.
+# bootstrap = "/my/sqlite/schema.sql"
+# }
+#
+# mysql {
+# # If any of the below files are set tls encryption is enabled
+# tls {
+# ca_file = "/etc/ssl/certs/my_ca.crt"
+# ca_path = "/etc/ssl/certs/"
+# certificate_file = "/etc/ssl/certs/private/client.crt"
+# private_key_file = "/etc/ssl/certs/private/client.key"
+# cipher = "DHE-RSA-AES256-SHA:AES128-SHA"
+# }
+# }
+#
+# postgres {
+# # Send application_name to the postgres server
+# # Only supported in PG 9.0 and greater. Defaults to yes.
+# send_application_name = yes
+# }
+#
+
# The dialect of SQL you want to use, this should usually match
# the driver you selected above.
#
# The connection pool is new for 3.0, and will be used in many
# modules, for all kinds of connection-related activity.
#
+ # When the server is not threaded, the connection pool
+ # limits are ignored, and only one connection is used.
+ #
pool {
# Number of connections to start
start = 5
#
# If these connections are all in use and a new one
# is requested, the request will NOT get a connection.
- max = 10
+ #
+ # Setting 'max' to LESS than the number of threads means
+ # that some threads may starve, and you will see errors
+ # like "No connections available and at max connection limit"
+ #
+ # Setting 'max' to MORE than the number of threads means
+ # that there are more connections than necessary.
+ #
+ max = ${thread[pool].max_servers}
# Spare connections to be left idle
#
#
sqlcounter dailycounter {
sql_module_instance = sql
- dialect = ${sql_module_instance}.dialect
+ dialect = ${modules.sql.dialect}
counter_name = Daily-Session-Time
check_name = Max-Daily-Session
sqlcounter monthlycounter {
sql_module_instance = sql
- dialect = ${sql_module_instance}.dialect
+ dialect = ${modules.sql.dialect}
counter_name = Monthly-Session-Time
check_name = Max-Monthly-Session
sqlcounter noresetcounter {
sql_module_instance = sql
- dialect = ${sql_module_instance}.dialect
+ dialect = ${modules.sql.dialect}
- counter_name = Max-All-Session-Time
+ counter_name = Max-All-Session-Time
check_name = Max-All-Session
key = User-Name
reset = never
# attribute.
sqlcounter expire_on_login {
sql_module_instance = sql
- dialect = ${sql_module_instance}.dialect
+ dialect = ${modules.sql.dialect}
- counter_name = Expire-After-Initial-Login
- check_name = Expire-After
- key = User-Name
- reset = never
+ counter_name = Expire-After-Initial-Login
+ check_name = Expire-After
+ key = User-Name
+ reset = never
$INCLUDE ${modconfdir}/sql/counter/${dialect}/${.:instance}.conf
}
--- /dev/null
+unbound dns {
+ # filename = "${raddbdir}/mods-config/unbound/default.conf"
+ # timeout = 3000
+}
# Unix /etc/passwd style authentication
#
+# This module calls the system functions to get the "known good"
+# password. This password is usually in the "crypt" form, and is
+# incompatible with CHAP, MS-CHAP, PEAP, etc.
+#
+# If passwords are in /etc/shadow, you will need to set the "group"
+# configuration in radiusd.conf. Look for "shadow", and follow the
+# instructions there.
+#
unix {
- # As of 1.1.0, the Unix module no longer reads,
- # or caches /etc/passwd, /etc/shadow, or /etc/group.
- # If you wish to cache those files, see the passwd
- # module.
- #
-
#
# The location of the "wtmp" file.
# The only use for 'radlast'. If you don't use
--- /dev/null
+# -*- text -*-
+#
+# $Id$
+
+#
+# This module is useful only for 'xlat'. To use it,
+# add it to the raddb/mods-enabled/ directory. Then,
+# use it on the right-hand side of a variable assignment.
+#
+# ... = "%{unpack:data 1 integer}"
+#
+# The arguments are three fields:
+#
+# data
+# Either &Attribute-Name
+# the name of the attribute to unpack.
+# MUST be a "string" or "octets" type.
+#
+# or 0xabcdef
+# e.g. hex data.
+#
+# 1
+# The offset into the string from which
+# it starts unpacking. The offset starts
+# at zero, for the first attribute.
+#
+# integer
+# the data type to unpack at that offset.
+# e.g. integer, ipaddr, byte, short, etc.
+#
+# e.g. if we have Class = 0x00000001020304, then
+#
+# %{unpack:&Class 4 short}
+#
+# will unpack octets 4 and 5 as a "short", which has
+# value 0x0304.
+#
+# This module is used when vendors put multiple fields
+# into one attribute of type "octets".
+#
+unpack {
+}
# id_length = 12
#
+ # If true, the authorize method of rlm_yubikey will attempt to split the
+ # value of User-Password, into the user's password, and the OTP token.
+ #
+ # If enabled and successful, the value of User-Password will be truncated
+ # and request:Yubikey-OTP will be added.
+ #
+# split = yes
+
+ #
# Decrypt mode - Tokens will be decrypted and processed locally
#
# The module itself does not provide persistent storage as this
#
pool {
# Number of connections to start
- start = 5
+ start = ${thread[pool].start_servers}
# Minimum number of connections to keep open
- min = 4
+ min = ${thread[pool].min_spare_servers}
# Maximum number of connections
#
# If these connections are all in use and a new one
# is requested, the request will NOT get a connection.
- max = 10
+ #
+ # NOTE: This should be greater than or equal to "min" above.
+ max = ${thread[pool].max_servers}
# Spare connections to be left idle
#
# NOTE: Idle connections WILL be closed if "idle_timeout"
- # is set.
- spare = 3
+ # is set. This should be less than or equal to "max" above.
+ spare = ${thread[pool].max_spare_servers}
# Number of uses before the connection is closed
#
- # 0 means "infinite"
+ # NOTE: A setting of 0 means infinite (no limit).
uses = 0
# The lifetime (in seconds) of the connection
+ #
+ # NOTE: A setting of 0 means infinite (no limit).
lifetime = 0
- # idle timeout (in seconds). A connection which is
+ # The idle timeout (in seconds). A connection which is
# unused for this length of time will be closed.
+ #
+ # NOTE: A setting of 0 means infinite (no timeout).
idle_timeout = 60
# Cycle over all connections in a pool instead of concentrating
# Replace the User-Name with the Stripped-User-Name, if it exists.
#
#DEFAULT
-# User-Name := "%{Stripped-User-Name:-%{User-Name}}"
+# User-Name := "%{%{Stripped-User-Name}:-%{User-Name}}"
# User-Name from the original request.
#
#DEFAULT
-# User-Name := `%{Stripped-User-Name:-%{User-Name}}`
+# User-Name := `%{%{Stripped-User-Name}:-%{User-Name}}`
#my %RAD_REPLY;
#This is for check items
#my %RAD_CHECK;
+# This is configuration items from "config" perl module configuration section
+#my %RAD_PERLCONF;
#
# This the remapping of return values
use constant L_PROXY=> 5;
use constant L_ACCT=> 6;
-# Same as src/include/radiusd.h
-use constant L_DBG=> 1;
-use constant L_AUTH=> 2;
-use constant L_INFO=> 3;
-use constant L_ERR=> 4;
-use constant L_PROXY=> 5;
-use constant L_ACCT=> 6;
-
# Global variables can persist across different calls to the module.
#
#
- # This query properly handles calls that span from the
- # previous reset period into the current period but
- # involves more work for the SQL server than those
- # below
- query = "SELECT SUM(acctsessiontime - \
- GREATEST((%b - UNIX_TIMESTAMP(acctstarttime)), 0)) \
- FROM radacct WHERE username = '%{${key}}' AND \
- UNIX_TIMESTAMP(acctstarttime) + acctsessiontime > '%b'"
+#
+# This query properly handles calls that span from the
+# previous reset period into the current period but
+# involves more work for the SQL server than those
+# below
+#
+query = "\
+ SELECT SUM(acctsessiontime - GREATEST((%b - UNIX_TIMESTAMP(acctstarttime)), 0)) \
+ FROM radacct \
+ WHERE username = '%{${key}}' \
+ AND UNIX_TIMESTAMP(acctstarttime) + acctsessiontime > '%b'"
- # This query ignores calls that started in a previous
- # reset period and continue into into this one. But it
- # is a little easier on the SQL server
-# query = "SELECT SUM(acctsessiontime) FROM radacct WHERE \
-# username = '%{${key}}' AND acctstarttime > FROM_UNIXTIME('%b')"
+#
+# This query ignores calls that started in a previous
+# reset period and continue into into this one. But it
+# is a little easier on the SQL server
+#
+#query = "\
+# SELECT SUM(acctsessiontime) \
+# FROM radacct \
+# WHERE username = '%{${key}}' \
+# AND acctstarttime > FROM_UNIXTIME('%b')"
- # This query is the same as above, but demonstrates an
- # additional counter parameter '%e' which is the
- # timestamp for the end of the period
-# query = "SELECT SUM(acctsessiontime) FROM radacct \
-# WHERE username = '%{${key}}' AND acctstarttime BETWEEN \
-# FROM_UNIXTIME('%b') AND FROM_UNIXTIME('%e')"
+#
+# This query is the same as above, but demonstrates an
+# additional counter parameter '%e' which is the
+# timestamp for the end of the period
+#
+#query = "\
+# SELECT SUM(acctsessiontime) \
+# FROM radacct \
+# WHERE username = '%{${key}}' \
+# AND acctstarttime BETWEEN FROM_UNIXTIME('%b') AND FROM_UNIXTIME('%e')"
- query = "SELECT TIME_TO_SEC(TIMEDIFF(NOW(), acctstarttime)) \
- FROM radacct \
- WHERE UserName='%{${key}}' \
- ORDER BY acctstarttime \
- LIMIT 1;"
+query = "\
+ SELECT TIMESTAMPDIFF(SECOND, acctstarttime, NOW()) \
+ FROM radacct \
+ WHERE UserName='%{${key}}' \
+ ORDER BY acctstarttime \
+ LIMIT 1;"
- # This query properly handles calls that span from the
- # previous reset period into the current period but
- # involves more work for the SQL server than those
- # below
- query = "SELECT SUM(acctsessiontime - \
- GREATEST((%b - UNIX_TIMESTAMP(acctstarttime)), 0)) \
- FROM radacct WHERE username='%{${key}}' AND \
- UNIX_TIMESTAMP(acctstarttime) + acctsessiontime > '%b'"
+#
+# This query properly handles calls that span from the
+# previous reset period into the current period but
+# involves more work for the SQL server than those
+# below
+#
+query = "\
+ SELECT SUM(acctsessiontime - GREATEST((%b - UNIX_TIMESTAMP(acctstarttime)), 0)) \
+ FROM radacct \
+ WHERE username='%{${key}}' \
+ AND UNIX_TIMESTAMP(acctstarttime) + acctsessiontime > '%b'"
- # This query ignores calls that started in a previous
- # reset period and continue into into this one. But it
- # is a little easier on the SQL server
-# query = "SELECT SUM(acctsessiontime) FROM radacct WHERE \
-# username='%{${key}}' AND acctstarttime > FROM_UNIXTIME('%b')"
+#
+# This query ignores calls that started in a previous
+# reset period and continue into into this one. But it
+# is a little easier on the SQL server
+#
+#query = "\
+# SELECT SUM(acctsessiontime) \
+# FROM radacct\
+# WHERE username='%{${key}}' \
+# AND acctstarttime > FROM_UNIXTIME('%b')"
- # This query is the same as above, but demonstrates an
- # additional counter parameter '%e' which is the
- # timestamp for the end of the period
-# query = "SELECT SUM(acctsessiontime) FROM radacct \
-# WHERE username='%{${key}}' AND acctstarttime BETWEEN \
-# FROM_UNIXTIME('%b') AND FROM_UNIXTIME('%e')"
+#
+# This query is the same as above, but demonstrates an
+# additional counter parameter '%e' which is the
+# timestamp for the end of the period
+#
+#query = "\
+# SELECT SUM(acctsessiontime) \
+# FROM radacct \
+# WHERE username='%{${key}}' \
+# AND acctstarttime BETWEEN FROM_UNIXTIME('%b') \
+# AND FROM_UNIXTIME('%e')"
- query = "SELECT IFNULL(SUM(AcctSessionTime),0) \
- FROM radacct \
- WHERE UserName='%{${key}}'"
+query = "\
+ SELECT IFNULL(SUM(AcctSessionTime),0) \
+ FROM radacct \
+ WHERE UserName='%{${key}}'"
- # This query properly handles calls that span from the
- # previous reset period into the current period but
- # involves more work for the SQL server than those
- # below
- query = "SELECT SUM(AcctSessionTime - \
- GREATER((%b - AcctStartTime::ABSTIME::INT4), 0)) \
- FROM radacct WHERE UserName='%{${key}}' AND \
- AcctStartTime::ABSTIME::INT4 + AcctSessionTime > '%b'"
+#
+# This query properly handles calls that span from the
+# previous reset period into the current period but
+# involves more work for the SQL server than those
+# below
+#
+query = "\
+ SELECT SUM(AcctSessionTime - GREATER((%b - AcctStartTime::ABSTIME::INT4), 0)) \
+ FROM radacct \
+ WHERE UserName='%{${key}}' \
+ AND AcctStartTime::ABSTIME::INT4 + AcctSessionTime > '%b'"
- # This query ignores calls that started in a previous
- # reset period and continue into into this one. But it
- # is a little easier on the SQL server
-# query = "SELECT SUM(AcctSessionTime) FROM radacct WHERE \
-# UserName='%{${key}}' AND AcctStartTime::ABSTIME::INT4 > '%b'"
+#
+# This query ignores calls that started in a previous
+# reset period and continue into into this one. But it
+# is a little easier on the SQL server
+#
+#query = "\
+# SELECT SUM(AcctSessionTime) \
+# FROM radacct \
+# WHERE UserName='%{${key}}' \
+# AND AcctStartTime::ABSTIME::INT4 > '%b'"
- # This query is the same as above, but demonstrates an
- # additional counter parameter '%e' which is the
- # timestamp for the end of the period
-# query = "SELECT SUM(AcctSessionTime) FROM radacct \
-# WHERE UserName='%{${key}}' AND AcctStartTime::ABSTIME::INT4 \
-# BETWEEN '%b' AND '%e'"
+#
+# This query is the same as above, but demonstrates an
+# additional counter parameter '%e' which is the
+# timestamp for the end of the period
+#
+#query = "\
+# SELECT SUM(AcctSessionTime) \
+# FROM radacct \
+# WHERE UserName='%{${key}}' \
+# AND AcctStartTime::ABSTIME::INT4 BETWEEN '%b' \
+# AND '%e'"
- query = "SELECT TIME_TO_SEC(TIMEDIFF(NOW(), acctstarttime)) \
- FROM radacct \
- WHERE UserName='%{${key}}' \
- ORDER BY acctstarttime \
- LIMIT 1;"
+query = "\
+ SELECT TIME_TO_SEC(TIMEDIFF(NOW(), acctstarttime)) \
+ FROM radacct \
+ WHERE UserName='%{${key}}' \
+ ORDER BY acctstarttime \
+ LIMIT 1;"
- # This query properly handles calls that span from the
- # previous reset period into the current period but
- # involves more work for the SQL server than those
- # below
- query = "SELECT SUM(AcctSessionTime - \
- GREATER((%b - AcctStartTime::ABSTIME::INT4), 0)) \
- FROM radacct WHERE UserName='%{${key}}' AND \
- AcctStartTime::ABSTIME::INT4 + AcctSessionTime > '%b'"
+# This query properly handles calls that span from the
+# previous reset period into the current period but
+# involves more work for the SQL server than those
+# below
+query = "\
+ SELECT SUM(AcctSessionTime - GREATER((%b - AcctStartTime::ABSTIME::INT4), 0)) \
+ FROM radacct \
+ WHERE UserName='%{${key}}' \
+ AND AcctStartTime::ABSTIME::INT4 + AcctSessionTime > '%b'"
+#
+# This query ignores calls that started in a previous
+# reset period and continue into into this one. But it
+# is a little easier on the SQL server
+#
+#query = "\
+# SELECT SUM(AcctSessionTime) \
+# FROM radacct \
+# WHERE UserName='%{${key}}' \
+# AND AcctStartTime::ABSTIME::INT4 > '%b'"
- # This query ignores calls that started in a previous
- # reset period and continue into into this one. But it
- # is a little easier on the SQL server
-# query = "SELECT SUM(AcctSessionTime) FROM radacct WHERE \
-# UserName='%{${key}}' AND AND AcctStartTime::ABSTIME::INT4 > '%b'"
-
- # This query is the same as above, but demonstrates an
- # additional counter parameter '%e' which is the
- # timestamp for the end of the period
-# query = "SELECT SUM(AcctSessionTime) FROM radacct \
-# WHERE UserName='%{${key}}' AND AcctStartTime::ABSTIME::INT4 \
-# BETWEEN '%b' AND '%e'"
+#
+# This query is the same as above, but demonstrates an
+# additional counter parameter '%e' which is the
+# timestamp for the end of the period
+#
+#query = "\
+# SELECT SUM(AcctSessionTime) \
+# FROM radacct \
+# WHERE UserName='%{${key}}' \
+# AND AcctStartTime::ABSTIME::INT4 BETWEEN '%b' AND '%e'"
- query = "SELECT SUM(AcctSessionTime) FROM radacct WHERE UserName='%{${key}}'"
+query = "\
+ SELECT SUM(AcctSessionTime) \
+ FROM radacct \
+ WHERE UserName='%{${key}}'"
- # This query properly handles calls that span from the
- # previous reset period into the current period but
- # involves more work for the SQL server than those
- # below
- query = "SELECT SUM(acctsessiontime - \
- GREATEST((%b - strftime('%s', acctstarttime)), 0)) \
- FROM radacct WHERE username = '%{${key}}' AND \
- (strftime('%s', acctstarttime) + acctsessiontime) > %b"
+#
+# This query properly handles calls that span from the
+# previous reset period into the current period but
+# involves more work for the SQL server than those
+# below
+#
+query = "\
+ SELECT SUM(acctsessiontime - GREATEST((%b - strftime('%%s', acctstarttime)), 0)) \
+ FROM radacct \
+ WHERE username = '%{${key}}' \
+ AND (strftime('%%s', acctstarttime) + acctsessiontime) > %b"
- # This query ignores calls that started in a previous
- # reset period and continue into into this one. But it
- # is a little easier on the SQL server
-# query = "SELECT SUM(acctsessiontime) FROM radacct WHERE \
-# username = '%{${key}}' AND acctstarttime > %b"
+#
+# This query ignores calls that started in a previous
+# reset period and continue into into this one. But it
+# is a little easier on the SQL server
+#
+#query = "\
+# SELECT SUM(acctsessiontime) \
+# FROM radacct \
+# WHERE \username = '%{${key}}' \
+# AND acctstarttime > %b"
- # This query is the same as above, but demonstrates an
- # additional counter parameter '%e' which is the
- # timestamp for the end of the period
-# query = "SELECT SUM(acctsessiontime) FROM radacct \
-# WHERE username = '%{${key}}' AND acctstarttime BETWEEN \
-# %b AND %e"
+#
+# This query is the same as above, but demonstrates an
+# additional counter parameter '%e' which is the
+# timestamp for the end of the period
+#
+#query = "\
+# SELECT SUM(acctsessiontime) FROM radacct \
+# WHERE username = '%{${key}}' \
+# AND acctstarttime BETWEEN %b \
+# AND %e"
- query = "SELECT GREATEST(strftime('%s', NOW()) - strftime('%s', acctstarttime), 0) AS expires \
- FROM radacct \
- WHERE username = '%{${key}}' \
- ORDER BY acctstarttime \
- LIMIT 1;"
+query = "\
+ SELECT GREATEST(strftime('%%s', NOW()) - strftime('%%s', acctstarttime), 0) AS expires \
+ FROM radacct \
+ WHERE username = '%{${key}}' \
+ ORDER BY acctstarttime \
+ LIMIT 1;"
- # This query properly handles calls that span from the
- # previous reset period into the current period but
- # involves more work for the SQL server than those
- # below
- query = "SELECT SUM(acctsessiontime - \
- GREATEST((%b - strftime('%s', acctstarttime)), 0)) \
- FROM radacct WHERE username = '%{${key}}' AND \
- (strftime('%s', acctstarttime) + acctsessiontime) > %b"
+#
+# This query properly handles calls that span from the
+# previous reset period into the current period but
+# involves more work for the SQL server than those
+# below
+#
+query = "\
+ SELECT SUM(acctsessiontime - GREATEST((%b - strftime('%%s', acctstarttime)), 0)) \
+ FROM radacct \
+ WHERE username = '%{${key}}' AND \
+ (strftime('%%s', acctstarttime) + acctsessiontime) > %b"
- # This query ignores calls that started in a previous
- # reset period and continue into into this one. But it
- # is a little easier on the SQL server
-# query = "SELECT SUM(acctsessiontime) FROM radacct WHERE \
-# username = '%{${key}}' AND acctstarttime > %b"
+#
+# This query ignores calls that started in a previous
+# reset period and continue into into this one. But it
+# is a little easier on the SQL server
+#
+#query = "\
+# SELECT SUM(acctsessiontime) \
+# FROM radacct \
+# WHERE username = '%{${key}}' \
+# AND acctstarttime > %b"
- # This query is the same as above, but demonstrates an
- # additional counter parameter '%e' which is the
- # timestamp for the end of the period
-# query = "SELECT SUM(acctsessiontime) FROM radacct \
-# WHERE username = '%{${key}}' AND acctstarttime BETWEEN \
-# %b AND %e"
+#
+# This query is the same as above, but demonstrates an
+# additional counter parameter '%e' which is the
+# timestamp for the end of the period
+#
+#query = "\
+# SELECT SUM(acctsessiontime) \
+# FROM radacct \
+# WHERE username = '%{${key}}' \
+# AND acctstarttime BETWEEN %b \
+# AND %e"
- query = "SELECT IFNULL(SUM(acctsessiontime),0) \
- FROM radacct \
- WHERE username = '%{${key}}'"
+query = "\
+ SELECT IFNULL(SUM(acctsessiontime),0) \
+ FROM radacct \
+ WHERE username = '%{${key}}'"
# -*- text -*-
-
-##
-## Queries to update the CUI table.
-##
+#
+# cui/mysql/queries.conf -- Queries to update a MySQL CUI table.
+#
+# $Id$
post-auth {
query = "\
VALUES \
('%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}', '%{Calling-Station-Id}', \
'%{User-Name}', '%{reply:Chargeable-User-Identity}', NULL) \
- ON DUPLICATE KEY UPDATE lastaccounting='0000-00-00 00:00:00', cui='%{reply:Chargeable-User-Identity}'"
+ ON DUPLICATE KEY UPDATE \
+ lastaccounting='0000-00-00 00:00:00', \
+ cui='%{reply:Chargeable-User-Identity}'"
}
UPDATE ${....cui_table} SET \
lastaccounting = CURRENT_TIMESTAMP \
WHERE clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND username = '%{User-Name}' \
- AND cui = '%{Chargeable-User-Identity}'"
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND username = '%{User-Name}' \
+ AND cui = '%{Chargeable-User-Identity}'"
}
interim-update {
query ="\
UPDATE ${....cui_table} SET \
lastaccounting = CURRENT_TIMESTAMP \
WHERE clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND username = '%{User-Name}' \
- AND cui = '%{Chargeable-User-Identity}'"
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND username = '%{User-Name}' \
+ AND cui = '%{Chargeable-User-Identity}'"
}
stop {
query ="\
- DELETE FROM ${....cui_table} WHERE \
- clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND username = '%{User-Name}' \
- AND cui = '%{Chargeable-User-Identity}'"
+ DELETE FROM ${....cui_table} \
+ WHERE clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND username = '%{User-Name}' \
+ AND cui = '%{Chargeable-User-Identity}'"
}
}
}
# -*- text -*-
-
-##
-## Queries to update the CUI table.
-##
+#
+# cui/postgresql/queries.conf -- Queries to update a PostgreSQL CUI table.
+#
+# $Id$
post-auth {
query = "\
INSERT INTO ${..cui_table} \
(clientipaddress, callingstationid, username, cui) \
VALUES \
- ('%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}', '%{Calling-Station-Id}', '%{User-Name}', '%{reply:Chargeable-User-Identity}')"
+ ('%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}', '%{Calling-Station-Id}', \
+ '%{User-Name}', '%{reply:Chargeable-User-Identity}')"
}
UPDATE ${....cui_table} SET \
lastaccounting = now() \
WHERE clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND username = '%{User-Name}' \
- AND cui = '%{Chargeable-User-Identity}'"
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND username = '%{User-Name}' \
+ AND cui = '%{Chargeable-User-Identity}'"
}
interim-update {
query ="\
UPDATE ${....cui_table} SET \
lastaccounting = now() \
WHERE clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND username = '%{User-Name}' \
- AND cui = '%{Chargeable-User-Identity}'"
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND username = '%{User-Name}' \
+ AND cui = '%{Chargeable-User-Identity}'"
}
stop {
query ="\
- DELETE FROM ${....cui_table} WHERE \
- clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND username = '%{User-Name}' \
- AND cui = '%{Chargeable-User-Identity}'"
+ DELETE FROM ${....cui_table} \
+ WHERE clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND username = '%{User-Name}' \
+ AND cui = '%{Chargeable-User-Identity}'"
}
}
}
);
CREATE RULE postauth_query AS ON INSERT TO cui
- WHERE EXISTS(SELECT 1 FROM cui WHERE (username, clientipaddress, callingstationid)=(NEW.username, NEW.clientipaddress, NEW.callingstationid))
- DO INSTEAD UPDATE cui SET lastaccounting ='-infinity'::timestamp with time zone, cui=NEW.cui WHERE (username, clientipaddress, callingstationid)=(NEW.username, NEW.clientipaddress, NEW.callingstationid);
+ WHERE EXISTS(SELECT 1 FROM cui WHERE (username, clientipaddress, callingstationid)=(NEW.username, NEW.clientipaddress, NEW.callingstationid))
+ DO INSTEAD UPDATE cui SET lastaccounting ='-infinity'::timestamp with time zone, cui=NEW.cui WHERE (username, clientipaddress, callingstationid)=(NEW.username, NEW.clientipaddress, NEW.callingstationid);
# -*- text -*-
-
-##
-## Queries to update the CUI table.
-##
+#
+# cui/sqlite/queries.conf -- Queries to update a sqlite CUI table.
+#
+# $Id$
post-auth {
query = "\
- INSERT IGNORE INTO ${..cui_table} \
+ INSERT OR REPLACE INTO ${..cui_table} \
(clientipaddress, callingstationid, username, cui, lastaccounting) \
VALUES \
('%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}', '%{Calling-Station-Id}', \
- '%{User-Name}', '%{reply:Chargeable-User-Identity}', NULL) \
- ON DUPLICATE KEY UPDATE lastaccounting='0000-00-00 00:00:00', cui='%{reply:Chargeable-User-Identity}'"
+ '%{User-Name}', '%{reply:Chargeable-User-Identity}', NULL)"
}
UPDATE ${....cui_table} SET \
lastaccounting = CURRENT_TIMESTAMP \
WHERE clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND username = '%{User-Name}' \
- AND cui = '%{Chargeable-User-Identity}'"
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND username = '%{User-Name}' \
+ AND cui = '%{Chargeable-User-Identity}'"
}
interim-update {
query ="\
UPDATE ${....cui_table} SET \
lastaccounting = CURRENT_TIMESTAMP \
WHERE clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND username = '%{User-Name}' \
- AND cui = '%{Chargeable-User-Identity}'"
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND username = '%{User-Name}' \
+ AND cui = '%{Chargeable-User-Identity}'"
}
stop {
query ="\
- DELETE FROM ${....cui_table} WHERE \
- clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND username = '%{User-Name}' \
- AND cui = '%{Chargeable-User-Identity}'"
+ DELETE FROM ${....cui_table} \
+ WHERE clientipaddress = '%{%{Packet-Src-IPv6-Address}:-%{Packet-Src-IP-Address}}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND username = '%{User-Name}' \
+ AND cui = '%{Chargeable-User-Identity}'"
}
}
}
# -*- text -*-
-##
-## ippool.conf -- MySQL queries for rlm_sqlippool
-##
-## $Id$
-
-# ## This series of queries allocates an IP address
-# allocate_clear = "UPDATE ${ippool_table} \
-# SET nasipaddress = '', pool_key = 0, \
-# callingstationid = '', username = '', \
-# expiry_time = NULL \
-# WHERE pool_key = '${pool_key}'"
-
-## This series of queries allocates an IP address
-## (Note: If your pool_key is set to Calling-Station-Id and not NAS-Port
-## then you may wish to delete the "AND nasipaddress = '%{Nas-IP-Address}'
-## from the WHERE clause)
-
-allocate_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, \
- callingstationid = '', username = '', \
- expiry_time = NULL \
- WHERE expiry_time <= NOW() - INTERVAL 1 SECOND \
- AND nasipaddress = '%{Nas-IP-Address}'"
-
-
-
-## The ORDER BY clause of this query tries to allocate the same IP-address
-## which user had last session...
-allocate_find = "SELECT framedipaddress FROM ${ippool_table} \
- WHERE pool_name = '%{control:Pool-Name}' AND (expiry_time < NOW() OR expiry_time IS NULL) \
- ORDER BY (username <> '%{User-Name}'), \
- (callingstationid <> '%{Calling-Station-Id}'), \
- expiry_time \
- LIMIT 1 \
- FOR UPDATE"
-
-# ## If you prefer to allocate a random IP address every time, i
-# ## use this query instead
-# allocate_find = "SELECT framedipaddress FROM ${ippool_table} \
-# WHERE pool_name = '%{control:Pool-Name}' \
-# AND expiry_time IS NULL \
-# ORDER BY RAND() \
-# LIMIT 1 \
-# FOR UPDATE"
-
-
-
-## If an IP could not be allocated, check to see if the pool exists or not
-## This allows the module to differentiate between a full pool and no pool
-## Note: If you are not running redundant pool modules this query may be
-## commented out to save running this query every time an ip is not allocated.
-pool_check = "SELECT id FROM ${ippool_table} \
- WHERE pool_name='%{control:Pool-Name}' LIMIT 1"
-
-
-## This is the final IP Allocation query, which saves the allocated ip details
-allocate-update = "UPDATE ${ippool_table} \
- SET nasipaddress = '%{NAS-IP-Address}', pool_key = '${pool_key}', \
- callingstationid = '%{Calling-Station-Id}', username = '%{User-Name}', \
- expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
- WHERE framedipaddress = '%I' AND expiry_time IS NULL"
-
-
-
-## This series of queries frees an IP number when an accounting
-## START record arrives
-start_update = "UPDATE ${ippool_table} \
- SET expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
- WHERE nasipaddress = '%{NAS-IP-Address}' AND pool_key = '${pool_key}' \
- AND username = '%{User-Name}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND framedipaddress = '%{Framed-IP-Address}'"
-
-## This series of queries frees an IP number when an accounting
-## STOP record arrives
+#
+# ippool-dhcp/mysql/queries.conf -- MySQL queries for rlm_sqlippool
+#
+# $Id$
+
+#
+# This series of queries allocates an IP address
+#
+#allocate_clear = "\
+# UPDATE ${ippool_table} \
+# SET \
+# nasipaddress = '', \
+# pool_key = 0, \
+# callingstationid = '', \
+# username = '', \
+# expiry_time = NULL \
+# WHERE pool_key = '${pool_key}'"
+
+#
+# This series of queries allocates an IP address
+# (Note: If your pool_key is set to Calling-Station-Id and not NAS-Port
+# then you may wish to delete the "AND nasipaddress = '%{Nas-IP-Address}'
+# from the WHERE clause)
+#
+allocate_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ username = '', \
+ expiry_time = NULL \
+ WHERE expiry_time <= NOW() - INTERVAL 1 SECOND \
+ AND nasipaddress = '%{Nas-IP-Address}'"
+
+#
+# The ORDER BY clause of this query tries to allocate the same IP-address
+# which user had last session...
+#
+allocate_find = "\
+ SELECT framedipaddress \
+ FROM ${ippool_table} \
+ WHERE pool_name = '%{control:Pool-Name}' \
+ AND (expiry_time < NOW() OR expiry_time IS NULL) \
+ ORDER BY \
+ (username <> '%{User-Name}'), \
+ (callingstationid <> '%{Calling-Station-Id}'), \
+ expiry_time \
+ LIMIT 1 \
+ OR UPDATE"
+
+#
+# If you prefer to allocate a random IP address every time, use this query instead
+#
+#allocate_find = "\
+# SELECT framedipaddress \
+# FROM ${ippool_table} \
+# WHERE pool_name = '%{control:Pool-Name}' \
+# AND expiry_time IS NULL \
+# ORDER BY RAND() \
+# LIMIT 1 \
+# FOR UPDATE"
+
+#
+# If an IP could not be allocated, check to see if the pool exists or not
+# This allows the module to differentiate between a full pool and no pool
+# Note: If you are not running redundant pool modules this query may be
+# commented out to save running this query every time an ip is not allocated.
+#
+pool_check = "\
+ SELECT id \
+ FROM ${ippool_table} \
+ WHERE pool_name='%{control:Pool-Name}' \
+ LIMIT 1"
+
+#
+# This is the final IP Allocation query, which saves the allocated ip details
+#
+allocate_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '%{NAS-IP-Address}', \
+ pool_key = '${pool_key}', \
+ callingstationid = '%{Calling-Station-Id}', \
+ username = '%{User-Name}', \
+ expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
+ WHERE framedipaddress = '%I' AND expiry_time IS NULL"
+
+#
+# This series of queries frees an IP number when an accounting
+# START record arrives
+#
+start_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
+ WHERE nasipaddress = '%{NAS-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND framedipaddress = '%{Framed-IP-Address}'"
+
+#
+# This series of queries frees an IP number when an accounting
+# STOP record arrives
+#
stop_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, callingstationid = '', username = '', \
- expiry_time = NULL \
- WHERE nasipaddress = '%{Nas-IP-Address}' AND pool_key = '${pool_key}' \
- AND username = '%{User-Name}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND framedipaddress = '%{Framed-IP-Address}'"
-
-
-
-## This series of queries frees an IP number when an accounting
-## ALIVE record arrives
-alive_update = "UPDATE ${ippool_table} \
- SET expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
- WHERE nasipaddress = '%{Nas-IP-Address}' AND pool_key = '${pool_key}' \
- AND username = '%{User-Name}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND framedipaddress = '%{Framed-IP-Address}'"
-
-
-
-## This series of queries frees the IP numbers allocate to a
-## NAS when an accounting ON record arrives
-on_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, callingstationid = '', username = '', \
- expiry_time = NULL \
- WHERE nasipaddress = '%{Nas-IP-Address}'"
-
-## This series of queries frees the IP numbers allocate to a
-## NAS when an accounting OFF record arrives
-off_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, callingstationid = '', username = '', \
- expiry_time = NULL \
- WHERE nasipaddress = '%{Nas-IP-Address}'"
-
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ username = '', \
+ expiry_time = NULL \
+ WHERE nasipaddress = '%{Nas-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND framedipaddress = '%{Framed-IP-Address}'"
+
+#
+# This series of queries frees an IP number when an accounting
+# ALIVE record arrives
+#
+alive_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
+ WHERE nasipaddress = '%{Nas-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND framedipaddress = '%{Framed-IP-Address}'"
+
+#
+# This series of queries frees the IP numbers allocate to a
+# NAS when an accounting ON record arrives
+#
+on_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ username = '', \
+ expiry_time = NULL \
+ WHERE nasipaddress = '%{Nas-IP-Address}'"
+
+#
+# This series of queries frees the IP numbers allocate to a
+# NAS when an accounting OFF record arrives
+#
+off_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ username = '', \
+ expiry_time = NULL \
+ WHERE nasipaddress = '%{Nas-IP-Address}'"
--- /dev/null
+# -*- text -*-
+#
+# ippool-dhcp/oracle/queries.conf -- Oracle queries for dhcp-ippool
+#
+# $id: 416d59802a1321c16b936bb5e63c288ca3634bcd $
+
+#
+# "START TRANSACTION" not required with Oracle
+#
+allocate_begin = ""
+start_begin = ""
+alive_begin = ""
+stop_begin = ""
+on_begin = ""
+off_begin = ""
+
+#
+# This query allocates an IP address from the Pool
+# It query tries to allocate to the user
+# either the same IP-address that they had last session
+# or the IP which has been unused for the longest period of time
+#
+allocate_find = "\
+ WITH POOLS AS (\
+ SELECT * \
+ FROM ${ippool_table} \
+ WHERE pool_name = '%{control:Pool-Name}' \
+ AND (\
+ pool_key = '${pool_key}' \
+ OR expiry_time = (\
+ SELECT MIN(expiry_time) \
+ FROM ${ippool_table} \
+ WHERE pool_name = '%{control:Pool-Name}' \
+ AND expiry_time < CURRENT_TIMESTAMP AND pool_key != '${pool_key}'\
+ )\
+ )\
+ ) \
+ SELECT framedipaddress \
+ FROM (\
+ SELECT framedipaddress \
+ FROM POOLS \
+ WHERE pool_key = '${pool_key}' \
+ OR (\
+ NOT EXISTS (\
+ SELECT 1 \
+ FROM POOLS \
+ WHERE pool_key = '${pool_key}'\
+ )\
+ )\
+ ) WHERE ROWNUM = 1 FOR UPDATE"
+
+#
+# This function is available if you want to use multiple pools
+#
+#allocate_find = "\
+ SELECT msqlippool('%{SQL-User-Name}','%{control:Pool-Name}') \
+ FROM dual"
+
+#
+# If you prefer to allocate a random IP address every time, use this query instead
+#
+#allocate_find = "\
+# SELECT framedipaddress \
+# FROM ${ippool_table}\
+# WHERE framedipaddress = (\
+# SELECT framedipaddress \
+# FROM (\
+# SELECT framedipaddress \
+# FROM ${ippool_table} \
+# WHERE pool_name = '%{control:Pool-Name}' \
+# AND expiry_time < CURRENT_TIMESTAMP \
+# ORDER BY DBMS_RANDOM.VALUE\
+# ) \
+# WHERE ROWNUM = 1\
+# ) \
+# FOR UPDATE"
+
+#
+# If an IP could not be allocated, check to see whether the pool exists or not
+# This allows the module to differentiate between a full pool and no pool
+# Note: If you are not running redundant pool modules this query may be commented
+# out to save running this query every time an ip is not allocated.
+#
+#pool_check = "\
+# SELECT id \
+# FROM (\
+# SELECT id \
+# FROM ${ippool_table} \
+# WHERE pool_name = '%{control:Pool-Name}'\
+# ) WHERE ROWNUM = 1"
+
+#
+# This query marks the IP address handed out by "allocate_find" as used
+# for the period of "lease_duration" after which time it may be reused.
+#
+allocate_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '%{NAS-IP-Address}', \
+ pool_key = '${pool_key}', \
+ callingstationid = '%{Calling-Station-id}', \
+ username = '%{SQL-User-Name}', \
+ expiry_time = CURRENT_TIMESTAMP + INTERVAL '${lease_duration}' SECOND(1) \
+ WHERE framedipaddress = '%I'"
+
+#
+# This query frees the IP address assigned to "pool_key" when a new request
+# comes in for the same "pool_key". This means that either you are losing
+# accounting Stop records or you use Calling-Station-id instead of NAS-Port
+# as your "pool_key" and your users are able to reconnect before your NAS
+# has timed out their previous session. (Generally on wireless networks)
+# (Note: If your pool_key is set to Calling-Station-id and not NAS-Port
+# then you may wish to delete the "AND nasipaddress = '%{NAS-IP-Address}'
+# from the WHERE clause)
+#
+allocate_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = CURRENT_TIMESTAMP - INTERVAL '1' SECOND(1) \
+ WHERE pool_key = '${pool_key}'"
+
+#
+# This query extends an IP address lease by "lease_duration" when an accounting
+# START record arrives
+#
+start_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = CURRENT_TIMESTAMP + INTERVAL '${lease_duration}' SECOND(1) \
+ WHERE nasipaddress = '%{NAS-IP-Address}' \
+ AND pool_name = '%{control:Pool-Name}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress = '%{Framed-IP-Address}'"
+
+#
+# This query frees an IP address when an accounting
+# STOP record arrives
+#
+stop_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = CURRENT_TIMESTAMP - INTERVAL '1' SECOND(1) \
+ WHERE pool_key = '${pool_key}'"
+
+#
+# This query extends an IP address lease by "lease_duration" when an accounting
+# ALIVE record arrives
+#
+alive_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = CURRENT_TIMESTAMP + INTERVAL '${lease_duration}' SECOND(1) \
+ WHERE pool_key = '${pool_key}' \
+ AND pool_name = '%{control:Pool-Name}' \
+ AND framedipaddress = '%{Framed-IP-Address}'"
+
+#
+# This query frees all IP addresses allocated to a NAS when an
+# accounting ON record arrives from that NAS
+#
+on_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = CURRENT_TIMESTAMP - INTERVAL '1' SECOND(1) \
+ WHERE nasipaddress = '%{NAS-IP-Address}'"
+
+#
+# This query frees all IP addresses allocated to a NAS when an
+# accounting OFF record arrives from that NAS
+#
+off_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = CURRENT_TIMESTAMP - INTERVAL '1' SECOND(1) \
+ WHERE nasipaddress = '%{NAS-IP-Address}'"
--- /dev/null
+CREATE TABLE radippool (
+ id INT PRIMARY KEY,
+ pool_name VARCHAR(30) NOT NULL,
+ framedipaddress VARCHAR(30) NOT NULL,
+ nasipaddress VARCHAR(30) NOT NULL,
+ pool_key VARCHAR(64) NOT NULL,
+ calledstationid VARCHAR(64),
+ callingstationid VARCHAR(64) NOT NULL,
+ expiry_time TIMESTAMP(0) NOT NULL,
+ username VARCHAR(100)
+);
+
+CREATE INDEX radippool_poolname_ipaddr ON radippool (pool_name, framedipaddress);
+CREATE INDEX radippool_poolname_expire ON radippool (pool_name, expiry_time);
+CREATE INDEX radippool_nasipaddr_key ON radippool (nasipaddress, pool_key);
+CREATE INDEX radippool_nasipaddr_calling ON radippool (nasipaddress, callingstationid);
+
+CREATE SEQUENCE radippool_seq START WITH 1 INCREMENT BY 1;
+
+CREATE OR REPLACE TRIGGER radippool_serialnumber
+ BEFORE INSERT OR UPDATE OF id ON radippool
+ FOR EACH ROW
+ BEGIN
+ IF ( :NEW.id = 0 OR :NEW.id IS NULL ) THEN
+ SELECT radippool_seq.NEXTVAL INTO :NEW.id FROM dual;
+ END IF;
+ END;
+/
# -*- text -*-
-##
-## ippool.conf -- SQLite queries for rlm_sqlippool
-##
-## $Id$
-
-# ## This series of queries allocates an IP address
-# allocate_clear = "UPDATE ${ippool_table} \
-# SET nasipaddress = '', pool_key = 0, \
-# callingstationid = '', username = '', \
-# expiry_time = NULL \
-# WHERE pool_key = '${pool_key}'"
-
-## This series of queries allocates an IP address
-## (Note: If your pool_key is set to Calling-Station-Id and not NAS-Port
-## then you may wish to delete the "AND nasipaddress = '%{Nas-IP-Address}'
-## from the WHERE clause)
-
-allocate_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, \
- callingstationid = '', username = '', \
- expiry_time = NULL \
- WHERE expiry_time <= NOW() - INTERVAL 1 SECOND \
- AND nasipaddress = '%{Nas-IP-Address}'"
-
-
-
-## The ORDER BY clause of this query tries to allocate the same IP-address
-## which user had last session...
-allocate_find = "SELECT framedipaddress FROM ${ippool_table} \
- WHERE pool_name = '%{control:Pool-Name}' AND (expiry_time < NOW() OR expiry_time IS NULL) \
- ORDER BY (username <> '%{User-Name}'), \
- (callingstationid <> '%{Calling-Station-Id}'), \
- expiry_time \
- LIMIT 1 \
- FOR UPDATE"
-
-# ## If you prefer to allocate a random IP address every time, i
-# ## use this query instead
-# allocate_find = "SELECT framedipaddress FROM ${ippool_table} \
-# WHERE pool_name = '%{control:Pool-Name}' \
-# AND expiry_time IS NULL \
-# ORDER BY RAND() \
-# LIMIT 1 \
-# FOR UPDATE"
-
-
-
-## If an IP could not be allocated, check to see if the pool exists or not
-## This allows the module to differentiate between a full pool and no pool
-## Note: If you are not running redundant pool modules this query may be
-## commented out to save running this query every time an ip is not allocated.
-pool_check = "SELECT id FROM ${ippool_table} \
- WHERE pool_name='%{control:Pool-Name}' LIMIT 1"
-
-
-## This is the final IP Allocation query, which saves the allocated ip details
-allocate_update = "UPDATE ${ippool_table} \
- SET nasipaddress = '%{NAS-IP-Address}', pool_key = '${pool_key}', \
- callingstationid = '%{Calling-Station-Id}', username = '%{User-Name}', \
- expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
- WHERE framedipaddress = '%I' AND expiry_time IS NULL"
-
-
-
-## This series of queries frees an IP number when an accounting
-## START record arrives
-start_update = "UPDATE ${ippool_table} \
- SET expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
- WHERE nasipaddress = '%{NAS-IP-Address}' AND pool_key = '${pool_key}' \
- AND username = '%{User-Name}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND framedipaddress = '%{Framed-IP-Address}'"
-
-## This series of queries frees an IP number when an accounting
-## STOP record arrives
-stop_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, callingstationid = '', username = '', \
- expiry_time = NULL \
- WHERE nasipaddress = '%{Nas-IP-Address}' AND pool_key = '${pool_key}' \
- AND username = '%{User-Name}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND framedipaddress = '%{Framed-IP-Address}'"
-
-
-
-## This series of queries frees an IP number when an accounting
-## ALIVE record arrives
-alive_update = "UPDATE ${ippool_table} \
- SET expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
- WHERE nasipaddress = '%{Nas-IP-Address}' AND pool_key = '${pool_key}' \
- AND username = '%{User-Name}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND framedipaddress = '%{Framed-IP-Address}'"
-
-
-
-## This series of queries frees the IP numbers allocate to a
-## NAS when an accounting ON record arrives
-on_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, callingstationid = '', username = '', \
- expiry_time = NULL \
- WHERE nasipaddress = '%{Nas-IP-Address}'"
-
-## This series of queries frees the IP numbers allocate to a
-## NAS when an accounting OFF record arrives
-off_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, callingstationid = '', username = '', \
- expiry_time = NULL \
- WHERE nasipaddress = '%{Nas-IP-Address}'"
-
+#
+# ippool-dhcp/sqlite/queries.conf -- SQLite queries for rlm_sqlippool
+#
+# $Id$
+
+#
+# This series of queries allocates an IP address
+#
+#allocate_clear = "\
+# UPDATE ${ippool_table} \
+# SET \
+# nasipaddress = '', \
+# pool_key = 0, \
+# callingstationid = '', \
+# username = '', \
+# expiry_time = NULL \
+# WHERE pool_key = '${pool_key}'"
+
+#
+# This series of queries allocates an IP address
+# (Note: If your pool_key is set to Calling-Station-Id and not NAS-Port
+# then you may wish to delete the "AND nasipaddress = '%{Nas-IP-Address}'
+# from the WHERE clause)
+#
+allocate_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ username = '', \
+ expiry_time = NULL \
+ WHERE expiry_time <= datetime(strftime('%%s', 'now') - 1, 'unixepoch') \
+ AND nasipaddress = '%{Nas-IP-Address}'"
+
+#
+# The ORDER BY clause of this query tries to allocate the same IP-address
+# which user had last session...
+#
+allocate_find = "\
+ SELECT framedipaddress \
+ FROM ${ippool_table} \
+ WHERE pool_name = '%{control:Pool-Name}' \
+ AND (\
+ ((expiry_time < datetime('now')) OR expiry_time IS NULL) \
+ OR (callingstationid = '%{Calling-Station-Id}') \
+ AND expiry_time > datetime('now')\
+ ) \
+ ORDER BY \
+ (callingstationid <> '%{Calling-Station-Id}'), \
+ expiry_time \
+ LIMIT 1"
+
+#
+# If you prefer to allocate a random IP address every time, use this query instead
+#
+#allocate_find = "\
+# SELECT framedipaddress FROM ${ippool_table} \
+# WHERE pool_name = '%{control:Pool-Name}' \
+# AND expiry_time IS NULL \
+# ORDER BY RAND() \
+# LIMIT 1 \
+# FOR UPDATE"
+
+#
+# If an IP could not be allocated, check to see if the pool exists or not
+# This allows the module to differentiate between a full pool and no pool
+# Note: If you are not running redundant pool modules this query may be
+# commented out to save running this query every time an ip is not allocated.
+#
+pool_check = "\
+ SELECT id \
+ FROM ${ippool_table} \
+ WHERE pool_name='%{control:Pool-Name}' \
+ LIMIT 1"
+
+#
+# This is the final IP Allocation query, which saves the allocated ip details
+#
+allocate_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '%{NAS-IP-Address}', \
+ pool_key = '${pool_key}', \
+ callingstationid = '%{Calling-Station-Id}', \
+ username = '%{User-Name}', \
+ expiry_time = datetime(strftime('%%s', 'now') + ${lease_duration}, 'unixepoch') \
+ WHERE framedipaddress = '%I' \
+ AND expiry_time IS NULL"
+
+#
+# The following queries are not used for DHCP IP assignment.
+#
+
+#
+# This series of queries frees an IP number when an accounting START record arrives
+#
+start_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = datetime(strftime('%%s', 'now') + ${lease_duration}, 'unixepoch') \
+ WHERE nasipaddress = '%{NAS-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND framedipaddress = '%{Framed-IP-Address}'"
+
+#
+# This series of queries frees an IP number when an accounting STOP record arrives
+#
+stop_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ username = '', \
+ expiry_time = NULL \
+ WHERE nasipaddress = '%{Nas-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND framedipaddress = '%{Framed-IP-Address}'"
+
+#
+# This series of queries frees an IP number when an accounting ALIVE record arrives
+#
+alive_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = datetime(strftime('%%s', 'now') + ${lease_duration}, 'unixepoch') \
+ WHERE nasipaddress = '%{Nas-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND framedipaddress = '%{Framed-IP-Address}'"
+
+#
+# This series of queries frees the IP numbers allocate to a
+# NAS when an accounting ON record arrives
+#
+on_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ username = '', \
+ expiry_time = NULL \
+ WHERE \nasipaddress = '%{Nas-IP-Address}'"
+
+#
+# This series of queries frees the IP numbers allocate to a
+# NAS when an accounting OFF record arrives
+#
+off_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ username = '', \
+ expiry_time = NULL \
+ WHERE nasipaddress = '%{Nas-IP-Address}'"
--- /dev/null
+CREATE TABLE radippool (
+ id int PRIMARY KEY,
+ pool_name varchar(30) NOT NULL,
+ framedipaddress varchar(30) NOT NULL,
+ nasipaddress varchar(30) NOT NULL DEFAULT '',
+ pool_key varchar(64) NOT NULL DEFAULT '',
+ calledstationid varchar(64),
+ callingstationid varchar(64) NOT NULL DEFAULT '',
+ expiry_time timestamp DEFAULT NULL,
+ username varchar(100)
+);
+
+-- Example of how to put IPs in the pool
+-- INSERT INTO radippool (id, pool_name, framedipaddress) VALUES (1, 'local', '192.168.5.10');
+-- INSERT INTO radippool (id, pool_name, framedipaddress) VALUES (2, 'local', '192.168.5.11');
+-- INSERT INTO radippool (id, pool_name, framedipaddress) VALUES (3, 'local', '192.168.5.12');
+-- INSERT INTO radippool (id, pool_name, framedipaddress) VALUES (4, 'local', '192.168.5.13');
+
# -*- text -*-
-##
-## ippool.conf -- MySQL queries for rlm_sqlippool
-##
-## $Id$
-
-# ## This series of queries allocates an IP address
-# allocate_clear = "UPDATE ${ippool_table} \
-# SET nasipaddress = '', pool_key = 0, \
-# callingstationid = '', username = '', \
-# expiry_time = NULL \
-# WHERE pool_key = '${pool_key}'"
-
-## This series of queries allocates an IP address
-## (Note: If your pool_key is set to Calling-Station-Id and not NAS-Port
-## then you may wish to delete the "AND nasipaddress = '%{Nas-IP-Address}'
-## from the WHERE clause)
-
-allocate_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, \
- callingstationid = '', username = '', \
- expiry_time = NULL \
- WHERE expiry_time <= NOW() - INTERVAL 1 SECOND \
- AND nasipaddress = '%{Nas-IP-Address}'"
-
-
-
-## The ORDER BY clause of this query tries to allocate the same IP-address
-## which user had last session...
-allocate_find = "SELECT framedipaddress FROM ${ippool_table} \
- WHERE pool_name = '%{control:Pool-Name}' AND (expiry_time < NOW() OR expiry_time IS NULL) \
- ORDER BY (username <> '%{User-Name}'), \
- (callingstationid <> '%{Calling-Station-Id}'), \
- expiry_time \
- LIMIT 1 \
- FOR UPDATE"
-
-# ## If you prefer to allocate a random IP address every time, i
-# ## use this query instead
-# allocate_find = "SELECT framedipaddress FROM ${ippool_table} \
-# WHERE pool_name = '%{control:Pool-Name}' \
-# AND expiry_time IS NULL \
-# ORDER BY RAND() \
-# LIMIT 1 \
-# FOR UPDATE"
-
-
-
-## If an IP could not be allocated, check to see if the pool exists or not
-## This allows the module to differentiate between a full pool and no pool
-## Note: If you are not running redundant pool modules this query may be
-## commented out to save running this query every time an ip is not allocated.
-pool_check = "SELECT id FROM ${ippool_table} \
- WHERE pool_name='%{control:Pool-Name}' LIMIT 1"
-
-
-## This is the final IP Allocation query, which saves the allocated ip details
-allocate_update = "UPDATE ${ippool_table} \
- SET nasipaddress = '%{NAS-IP-Address}', pool_key = '${pool_key}', \
- callingstationid = '%{Calling-Station-Id}', username = '%{User-Name}', \
- expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
- WHERE framedipaddress = '%I' AND expiry_time IS NULL"
-
-
-
-## This series of queries frees an IP number when an accounting
-## START record arrives
-start_update = "UPDATE ${ippool_table} \
- SET expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
- WHERE nasipaddress = '%{NAS-IP-Address}' AND pool_key = '${pool_key}' \
- AND username = '%{User-Name}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND framedipaddress = '%{Framed-IP-Address}'"
-
-## This series of queries frees an IP number when an accounting
-## STOP record arrives
-stop_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, callingstationid = '', username = '', \
- expiry_time = NULL \
- WHERE nasipaddress = '%{Nas-IP-Address}' AND pool_key = '${pool_key}' \
- AND username = '%{User-Name}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND framedipaddress = '%{Framed-IP-Address}'"
-
-
-
-## This series of queries frees an IP number when an accounting
-## ALIVE record arrives
-alive_update = "UPDATE ${ippool_table} \
- SET expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
- WHERE nasipaddress = '%{Nas-IP-Address}' AND pool_key = '${pool_key}' \
- AND username = '%{User-Name}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND framedipaddress = '%{Framed-IP-Address}'"
-
-
-
-## This series of queries frees the IP numbers allocate to a
-## NAS when an accounting ON record arrives
-on_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, callingstationid = '', username = '', \
- expiry_time = NULL \
- WHERE nasipaddress = '%{Nas-IP-Address}'"
-
-## This series of queries frees the IP numbers allocate to a
-## NAS when an accounting OFF record arrives
-off_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, callingstationid = '', username = '', \
- expiry_time = NULL \
- WHERE nasipaddress = '%{Nas-IP-Address}'"
-
+#
+# ippool/mysql/queries.conf -- MySQL queries for rlm_sqlippool
+#
+# $Id$
+
+#
+# This series of queries allocates an IP address
+#
+#allocate_clear = "\
+# UPDATE ${ippool_table} \
+# SET \
+# nasipaddress = '', \
+# pool_key = 0, \
+# callingstationid = '', \
+# username = '', \
+# expiry_time = NULL \
+# WHERE pool_key = '${pool_key}'"
+
+#
+# This series of queries allocates an IP address
+# (Note: If your pool_key is set to Calling-Station-Id and not NAS-Port
+# then you may wish to delete the "AND nasipaddress = '%{Nas-IP-Address}'
+# from the WHERE clause)
+#
+allocate_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ username = '', \
+ expiry_time = NULL \
+ WHERE expiry_time <= NOW() - INTERVAL 1 SECOND \
+ AND nasipaddress = '%{Nas-IP-Address}'"
+
+#
+# The ORDER BY clause of this query tries to allocate the same IP-address
+# which user had last session...
+#
+allocate_find = "\
+ SELECT framedipaddress FROM ${ippool_table} \
+ WHERE pool_name = '%{control:Pool-Name}' \
+ AND (expiry_time < NOW() OR expiry_time IS NULL) \
+ ORDER BY \
+ (username <> '%{User-Name}'), \
+ (callingstationid <> '%{Calling-Station-Id}'), \
+ expiry_time \
+ LIMIT 1 \
+ FOR UPDATE"
+
+#
+# If you prefer to allocate a random IP address every time, use this query instead.
+#
+#allocate_find = "\
+# SELECT framedipaddress FROM ${ippool_table} \
+# WHERE pool_name = '%{control:Pool-Name}' \
+# AND expiry_time IS NULL \
+# ORDER BY \
+# RAND() \
+# LIMIT 1 \
+# FOR UPDATE"
+
+#
+# If an IP could not be allocated, check to see if the pool exists or not
+# This allows the module to differentiate between a full pool and no pool
+# Note: If you are not running redundant pool modules this query may be
+# commented out to save running this query every time an ip is not allocated.
+#
+pool_check = "\
+ SELECT id \
+ FROM ${ippool_table} \
+ WHERE pool_name='%{control:Pool-Name}' \
+ LIMIT 1"
+
+#
+# This is the final IP Allocation query, which saves the allocated ip details.
+#
+allocate_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '%{NAS-IP-Address}', pool_key = '${pool_key}', \
+ callingstationid = '%{Calling-Station-Id}', \
+ username = '%{User-Name}', expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
+ WHERE framedipaddress = '%I' \
+ AND expiry_time IS NULL"
+
+#
+# This series of queries frees an IP number when an accounting START record arrives.
+#
+start_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
+ WHERE nasipaddress = '%{NAS-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND framedipaddress = '%{Framed-IP-Address}'"
+
+#
+# This series of queries frees an IP number when an accounting STOP record arrives.
+#
+stop_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ username = '', \
+ expiry_time = NULL \
+ WHERE nasipaddress = '%{Nas-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND framedipaddress = '%{Framed-IP-Address}'"
+
+#
+# This series of queries frees an IP number when an accounting ALIVE record arrives.
+#
+alive_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
+ WHERE nasipaddress = '%{Nas-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND framedipaddress = '%{Framed-IP-Address}'"
+
+#
+# This series of queries frees the IP numbers allocate to a
+# NAS when an accounting ON record arrives
+#
+on_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ username = '', \
+ expiry_time = NULL \
+ WHERE nasipaddress = '%{Nas-IP-Address}'"
+
+#
+# This series of queries frees the IP numbers allocate to a
+# NAS when an accounting OFF record arrives
+#
+off_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ username = '', \
+ expiry_time = NULL \
+ WHERE nasipaddress = '%{Nas-IP-Address}'"
# -*- text -*-
-##
-## ippool.conf -- Oracle queries for rlm_sqlippool
-##
-## $Id$
+#
+# ippool/oracle/queries.conf -- Oracle queries for rlm_sqlippool
+#
+# $Id$
allocate_begin = "commit"
start_begin = "commit"
on_begin = "commit"
off_begin = "commit"
- ## This query allocates an IP address from the Pool
- ## The ORDER BY clause of this query tries to allocate the same IP-address
- ## to the user that they had last session...
- allocate_find = "SELECT framedipaddress FROM ${ippool_table} \
- WHERE pool_name = '%{control:Pool-Name}' AND expiry_time < current_timestamp \
- AND rownum <= 1 \
- ORDER BY (username <> '%{SQL-User-Name}'), \
- (callingstationid <> '%{Calling-Station-Id}'), expiry_time \
- FOR UPDATE"
-
- ## This function is available if you want to use multiple pools
-# allocate_find = "select msqlippool('%{SQL-User-Name}','%{control:Pool-Name}') from dual"
-
- ## If you prefer to allocate a random IP address every time, use this query instead
- #allocate_find = "SELECT framedipaddress FROM ${ippool_table} \
- # WHERE pool_name = '%{control:Pool-Name}' AND expiry_time < current_timestamp \
-# AND rownum <= 1 \
- # ORDER BY RANDOM() \
- # FOR UPDATE"
-
-
- ## If an IP could not be allocated, check to see whether the pool exists or not
- ## This allows the module to differentiate between a full pool and no pool
- ## Note: If you are not running redundant pool modules this query may be commented
- ## out to save running this query every time an ip is not allocated.
- pool_check = "SELECT id FROM (SELECT id FROM ${ippool_table} \
- WHERE pool_name='%{control:Pool-Name}') WHERE ROWNUM = 1"
-
-
- ## This query marks the IP address handed out by "allocate-find" as used
- ## for the period of "lease_duration" after which time it may be reused.
- allocate_update = "UPDATE ${ippool_table} \
- SET nasipaddress = '%{NAS-IP-Address}', pool_key = '${pool_key}', \
- callingstationid = '%{Calling-Station-Id}', username = '%{SQL-User-Name}', \
- expiry_time = current_timestamp + INTERVAL '${lease_duration}' second(1) \
- WHERE framedipaddress = '%I'"
-
-
- ## This query frees the IP address assigned to "pool_key" when a new request
- ## comes in for the same "pool_key". This means that either you are losing
- ## accounting Stop records or you use Calling-Station-Id instead of NAS-Port
- ## as your "pool_key" and your users are able to reconnect before your NAS
- ## has timed out their previous session. (Generally on wireless networks)
- ## (Note: If your pool_key is set to Calling-Station-Id and not NAS-Port
- ## then you may wish to delete the "AND nasipaddress = '%{Nas-IP-Address}'
- ## from the WHERE clause)
- allocate_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, callingstationid = '', \
- expiry_time = current_timestamp - INTERVAL '1' second(1) \
- WHERE pool_key = '${pool_key}'"
-
-
- ## This query extends an IP address lease by "lease_duration" when an accounting
- ## START record arrives
- start_update = "UPDATE ${ippool_table} \
- SET expiry_time = current_timestamp + INTERVAL '${lease_duration}' second(1) \
- WHERE nasipaddress = '%{NAS-IP-Address}' \
- AND pool_key = '${pool_key}'"
-
-
- ## This query frees an IP address when an accounting
- ## STOP record arrives
- stop_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, callingstationid = '', \
- expiry_time = current_timestamp - INTERVAL '1' second(1) \
- WHERE nasipaddress = '%{Nas-IP-Address}' \
- AND pool_key = '${pool_key}' \
- AND username = '%{SQL-User-Name}' \
- AND callingstationid = '%{Calling-Station-Id}'"
-
-
-## This query extends an IP address lease by "lease_duration" when an accounting
-## ALIVE record arrives
-alive_update = "UPDATE ${ippool_table} \
- SET expiry_time = current_timestamp + INTERVAL '${lease_duration}' second(1) \
- WHERE nasipaddress = '%{Nas-IP-Address}' \
- AND pool_key = '${pool_key}' \
- AND framedipaddress = '%{Framed-IP-Address}' \
- AND username = '%{SQL-User-Name}' \
- AND callingstationid = '%{Calling-Station-Id}'"
-
-
-## This query frees all IP addresses allocated to a NAS when an
-## accounting ON record arrives from that NAS
-on_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, callingstationid = '', \
- expiry_time = current_timestamp - INTERVAL '1' second(1) \
- WHERE nasipaddress = '%{Nas-IP-Address}'"
-
-
-## This query frees all IP addresses allocated to a NAS when an
-## accounting OFF record arrives from that NAS
-off_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, callingstationid = '', \
- expiry_time = current_timestamp - INTERVAL '1' second(1) \
- WHERE nasipaddress = '%{Nas-IP-Address}'"
-
+#
+# This query allocates an IP address from the Pool
+# The ORDER BY clause of this query tries to allocate the same IP-address
+# to the user that they had last session...
+#
+allocate_find = "\
+ SELECT framedipaddress \
+ FROM ${ippool_table} \
+ WHERE pool_name = '%{control:Pool-Name}' \
+ AND expiry_time < current_timestamp \
+ AND rownum <= 1 \
+ ORDER BY \
+ (username <> '%{SQL-User-Name}'), \
+ (callingstationid <> '%{Calling-Station-Id}'), \
+ expiry_time \
+ FOR UPDATE"
+
+#
+# This function is available if you want to use multiple pools
+#
+#allocate_find = "\
+# SELECT msqlippool('%{SQL-User-Name}','%{control:Pool-Name}') \
+# FROM dual"
+
+#
+# If you prefer to allocate a random IP address every time, use this query instead
+#
+#allocate_find = "\
+# SELECT framedipaddress \
+# FROM ${ippool_table} \
+# WHERE pool_name = '%{control:Pool-Name}' \
+# AND expiry_time < current_timestamp \
+# AND rownum <= 1 \
+# ORDER BY RANDOM() \
+# FOR UPDATE"
+
+#
+# If an IP could not be allocated, check to see whether the pool exists or not
+# This allows the module to differentiate between a full pool and no pool
+# Note: If you are not running redundant pool modules this query may be commented
+# out to save running this query every time an ip is not allocated.
+#
+pool_check = "\
+ SELECT id \
+ FROM (\
+ SELECT id \
+ FROM ${ippool_table} \
+ WHERE pool_name='%{control:Pool-Name}'\
+ ) \
+ WHERE ROWNUM = 1"
+
+#
+# This query marks the IP address handed out by "allocate-find" as used
+# for the period of "lease_duration" after which time it may be reused.
+#
+allocate_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '%{NAS-IP-Address}', \
+ pool_key = '${pool_key}', \
+ callingstationid = '%{Calling-Station-Id}', \
+ username = '%{SQL-User-Name}', \
+ expiry_time = current_timestamp + INTERVAL '${lease_duration}' second(1) \
+ WHERE framedipaddress = '%I'"
+
+#
+# This query frees the IP address assigned to "pool_key" when a new request
+# comes in for the same "pool_key". This means that either you are losing
+# accounting Stop records or you use Calling-Station-Id instead of NAS-Port
+# as your "pool_key" and your users are able to reconnect before your NAS
+# has timed out their previous session. (Generally on wireless networks)
+# (Note: If your pool_key is set to Calling-Station-Id and not NAS-Port
+# then you may wish to delete the "AND nasipaddress = '%{Nas-IP-Address}'
+# from the WHERE clause)
+#
+allocate_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ expiry_time = current_timestamp - INTERVAL '1' second(1) \
+ WHERE pool_key = '${pool_key}'"
+
+#
+# This query extends an IP address lease by "lease_duration" when an accounting
+# START record arrives
+#
+start_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = current_timestamp + INTERVAL '${lease_duration}' second(1) \
+ WHERE nasipaddress = '%{NAS-IP-Address}' \
+ AND pool_key = '${pool_key}'"
+
+#
+# This query frees an IP address when an accounting STOP record arrives
+#
+stop_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ expiry_time = current_timestamp - INTERVAL '1' second(1) \
+ WHERE nasipaddress = '%{Nas-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{SQL-User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}'"
+
+#
+# This query extends an IP address lease by "lease_duration" when an accounting
+# ALIVE record arrives
+#
+alive_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = current_timestamp + INTERVAL '${lease_duration}' second(1) \
+ WHERE nasipaddress = '%{Nas-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress = '%{Framed-IP-Address}' \
+ AND username = '%{SQL-User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}'"
+
+#
+# This query frees all IP addresses allocated to a NAS when an
+# accounting ON record arrives from that NAS
+#
+on_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ expiry_time = current_timestamp - INTERVAL '1' second(1) \
+ WHERE nasipaddress = '%{Nas-IP-Address}'"
+
+#
+# This query frees all IP addresses allocated to a NAS when an
+# accounting OFF record arrives from that NAS
+#
+off_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ expiry_time = current_timestamp - INTERVAL '1' second(1) \
+ WHERE nasipaddress = '%{Nas-IP-Address}'"
CREATE TABLE radippool (
- id INT PRIMARY KEY,
- pool_name VARCHAR(30) NOT NULL,
- framedipaddress VARCHAR(30) NOT NULL,
- nasipaddress VARCHAR(30) NOT NULL,
- pool_key INT NOT NULL,
- CalledStationId VARCHAR(64),
- CallingStationId VARCHAR(64) NOT NULL,
- expiry_time timestamp(0) NOT NULL,
- username VARCHAR(100)
+ id INT PRIMARY KEY,
+ pool_name VARCHAR(30) NOT NULL,
+ framedipaddress VARCHAR(30) NOT NULL,
+ nasipaddress VARCHAR(30) NOT NULL,
+ pool_key INT NOT NULL,
+ CalledStationId VARCHAR(64),
+ CallingStationId VARCHAR(64) NOT NULL,
+ expiry_time timestamp(0) NOT NULL,
+ username VARCHAR(100)
);
CREATE INDEX radippool_poolname_ipaadr ON radippool (pool_name, framedipaddress);
CREATE SEQUENCE radippool_seq START WITH 1 INCREMENT BY 1;
CREATE OR REPLACE TRIGGER radippool_serialnumber
- BEFORE INSERT OR UPDATE OF id ON radippool
- FOR EACH ROW
- BEGIN
- if ( :new.id = 0 or :new.id is null ) then
- SELECT radippool_seq.nextval into :new.id from dual;
- end if;
- END;
+ BEFORE INSERT OR UPDATE OF id ON radippool
+ FOR EACH ROW
+ BEGIN
+ if ( :new.id = 0 or :new.id is null ) then
+ SELECT radippool_seq.nextval into :new.id from dual;
+ end if;
+ END;
/
# -*- text -*-
-##
-## ippool.conf -- PostgreSQL queries for rlm_sqlippool
-##
-## $Id$
-
- ## This query allocates an IP address from the Pool
- ## The ORDER BY clause of this query tries to allocate the same IP-address
- ## to the user that they had last session...
- allocate_find = "SELECT framedipaddress FROM ${ippool_table} \
- WHERE pool_name = '%{control:Pool-Name}' AND expiry_time < 'now'::timestamp(0) \
- ORDER BY (username <> '%{SQL-User-Name}'), \
- (callingstationid <> '%{Calling-Station-Id}'), expiry_time \
- LIMIT 1 \
- FOR UPDATE"
-
- ## If you prefer to allocate a random IP address every time, use this query instead
- #allocate_find = "SELECT framedipaddress FROM ${ippool_table} \
- # WHERE pool_name = '%{control:Pool-Name}' AND expiry_time < 'now'::timestamp(0) \
- # ORDER BY RANDOM() \
- # LIMIT 1 \
- # FOR UPDATE"
-
-
- ## If an IP could not be allocated, check to see whether the pool exists or not
- ## This allows the module to differentiate between a full pool and no pool
- ## Note: If you are not running redundant pool modules this query may be commented
- ## out to save running this query every time an ip is not allocated.
- pool_check = "SELECT id FROM ${ippool_table} \
- WHERE pool_name='%{control:Pool-Name}' LIMIT 1"
-
-
- ## This query marks the IP address handed out by "allocate-find" as used
- ## for the period of "lease_duration" after which time it may be reused.
- allocate_update = "UPDATE ${ippool_table} \
- SET nasipaddress = '%{NAS-IP-Address}', pool_key = '${pool_key}', \
- callingstationid = '%{Calling-Station-Id}', username = '%{SQL-User-Name}', \
- expiry_time = 'now'::timestamp(0) + '${lease_duration} second'::interval \
- WHERE framedipaddress = '%I'"
-
-
- ## This query frees the IP address assigned to "pool_key" when a new request
- ## comes in for the same "pool_key". This means that either you are losing
- ## accounting Stop records or you use Calling-Station-Id instead of NAS-Port
- ## as your "pool_key" and your users are able to reconnect before your NAS
- ## has timed out their previous session. (Generally on wireless networks)
- ## (Note: If your pool_key is set to Calling-Station-Id and not NAS-Port
- ## then you may wish to delete the "AND nasipaddress = '%{Nas-IP-Address}'
- ## from the WHERE clause)
- allocate_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, callingstationid = '', \
- expiry_time = 'now'::timestamp(0) - '1 second'::interval \
- WHERE nasipaddress = '%{NAS-IP-Address}' \
- AND pool_key = '${pool_key}'"
-
-
- ## This query extends an IP address lease by "lease_duration" when an accounting
- ## START record arrives
- start_update = "UPDATE ${ippool_table} \
- SET expiry_time = 'now'::timestamp(0) + '${lease_duration} second'::interval \
- WHERE nasipaddress = '%{NAS-IP-Address}' \
- AND pool_key = '${pool_key}'"
-
-
- ## This query frees an IP address when an accounting
- ## STOP record arrives
- stop_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, callingstationid = '', \
- expiry_time = 'now'::timestamp(0) - '1 second'::interval \
- WHERE nasipaddress = '%{Nas-IP-Address}' \
- AND pool_key = '${pool_key}' \
- AND username = '%{SQL-User-Name}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND framedipaddress = '%{Framed-IP-Address}'"
-
-
- ## This query extends an IP address lease by "lease_duration" when an accounting
- ## ALIVE record arrives
- alive_update = "UPDATE ${ippool_table} \
- SET expiry_time = 'now'::timestamp(0) + '${lease_duration} seconds'::interval \
- WHERE nasipaddress = '%{Nas-IP-Address}' \
- AND pool_key = '${pool_key}' \
- AND framedipaddress = '%{Framed-IP-Address}' \
- AND username = '%{SQL-User-Name}' \
- AND callingstationid = '%{Calling-Station-Id}'"
-
-
- ## This query frees all IP addresses allocated to a NAS when an
- ## accounting ON record arrives from that NAS
- on_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, callingstationid = '', \
- expiry_time = 'now'::timestamp(0) - '1 second'::interval \
- WHERE nasipaddress = '%{Nas-IP-Address}'"
-
-
- ## This query frees all IP addresses allocated to a NAS when an
- ## accounting OFF record arrives from that NAS
- off_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, callingstationid = '', \
- expiry_time = 'now'::timestamp(0) - '1 second'::interval \
- WHERE nasipaddress = '%{Nas-IP-Address}'"
-
+#
+# ippool/postgresql/queries.conf -- PostgreSQL queries for rlm_sqlippool
+#
+# $Id$
+
+#
+# This query allocates an IP address from the Pool
+# The ORDER BY clause of this query tries to allocate the same IP-address
+# to the user that they had last session...
+#
+allocate_find = "\
+ SELECT framedipaddress \
+ FROM ${ippool_table} \
+ WHERE pool_name = '%{control:Pool-Name}' \
+ AND expiry_time < 'now'::timestamp(0) \
+ ORDER BY \
+ (username <> '%{SQL-User-Name}'), \
+ (callingstationid <> '%{Calling-Station-Id}'), \
+ expiry_time \
+ LIMIT 1 \
+ FOR UPDATE"
+
+#
+# If you prefer to allocate a random IP address every time, use this query instead
+#
+allocate_find = "\
+ SELECT framedipaddress FROM ${ippool_table} \
+ WHERE pool_name = '%{control:Pool-Name}' AND expiry_time < 'now'::timestamp(0) \
+ ORDER BY RANDOM() \
+ LIMIT 1 \
+ FOR UPDATE"
+
+#
+# If an IP could not be allocated, check to see whether the pool exists or not
+# This allows the module to differentiate between a full pool and no pool
+# Note: If you are not running redundant pool modules this query may be commented
+# out to save running this query every time an ip is not allocated.
+#
+pool_check = "\
+ SELECT id \
+ FROM ${ippool_table} \
+ WHERE pool_name='%{control:Pool-Name}' \
+ LIMIT 1"
+
+#
+# This query marks the IP address handed out by "allocate-find" as used
+# for the period of "lease_duration" after which time it may be reused.
+#
+allocate_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '%{NAS-IP-Address}', \
+ pool_key = '${pool_key}', \
+ callingstationid = '%{Calling-Station-Id}', \
+ username = '%{SQL-User-Name}', \
+ expiry_time = 'now'::timestamp(0) + '${lease_duration} second'::interval \
+ WHERE framedipaddress = '%I'"
+
+#
+# This query frees the IP address assigned to "pool_key" when a new request
+# comes in for the same "pool_key". This means that either you are losing
+# accounting Stop records or you use Calling-Station-Id instead of NAS-Port
+# as your "pool_key" and your users are able to reconnect before your NAS
+# has timed out their previous session. (Generally on wireless networks)
+# (Note: If your pool_key is set to Calling-Station-Id and not NAS-Port
+# then you may wish to delete the "AND nasipaddress = '%{Nas-IP-Address}'
+# from the WHERE clause)
+#
+allocate_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ expiry_time = 'now'::timestamp(0) - '1 second'::interval \
+ WHERE nasipaddress = '%{NAS-IP-Address}' \
+ AND pool_key = '${pool_key}'"
+
+#
+# This query extends an IP address lease by "lease_duration" when an accounting
+# START record arrives
+#
+start_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = 'now'::timestamp(0) + '${lease_duration} second'::interval \
+ WHERE nasipaddress = '%{NAS-IP-Address}' \
+ AND pool_key = '${pool_key}'"
+
+#
+# This query frees an IP address when an accounting
+# STOP record arrives
+#
+stop_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ expiry_time = 'now'::timestamp(0) - '1 second'::interval \
+ WHERE nasipaddress = '%{Nas-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{SQL-User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND framedipaddress = '%{Framed-IP-Address}'"
+
+#
+# This query extends an IP address lease by "lease_duration" when an accounting
+# ALIVE record arrives
+#
+alive_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = 'now'::timestamp(0) + '${lease_duration} seconds'::interval \
+ WHERE nasipaddress = '%{Nas-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ AND framedipaddress = '%{Framed-IP-Address}' \
+ AND username = '%{SQL-User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}'"
+
+#
+# This query frees all IP addresses allocated to a NAS when an
+# accounting ON record arrives from that NAS
+#
+on_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ expiry_time = 'now'::timestamp(0) - '1 second'::interval \
+ WHERE nasipaddress = '%{Nas-IP-Address}'"
+
+#
+# This query frees all IP addresses allocated to a NAS when an
+# accounting OFF record arrives from that NAS
+#
+off_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ expiry_time = 'now'::timestamp(0) - '1 second'::interval \
+ WHERE nasipaddress = '%{Nas-IP-Address}'"
# -*- text -*-
-##
-## ippool.conf -- SQLite queries for rlm_sqlippool
-##
-## $Id$
-
-# ## This series of queries allocates an IP address
-# allocate_clear = "UPDATE ${ippool_table} \
-# SET nasipaddress = '', pool_key = 0, \
-# callingstationid = '', username = '', \
-# expiry_time = NULL \
-# WHERE pool_key = '${pool_key}'"
-
-## This series of queries allocates an IP address
-## (Note: If your pool_key is set to Calling-Station-Id and not NAS-Port
-## then you may wish to delete the "AND nasipaddress = '%{Nas-IP-Address}'
-## from the WHERE clause)
-
- allocate_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, \
- callingstationid = '', username = '', \
- expiry_time = NULL \
- WHERE expiry_time <= NOW() - INTERVAL 1 SECOND \
- AND nasipaddress = '%{Nas-IP-Address}'"
-
-
-
-## The ORDER BY clause of this query tries to allocate the same IP-address
-## which user had last session...
-allocate_find = "SELECT framedipaddress FROM ${ippool_table} \
- WHERE pool_name = '%{control:Pool-Name}' AND (expiry_time < NOW() OR expiry_time IS NULL) \
- ORDER BY (username <> '%{User-Name}'), \
- (callingstationid <> '%{Calling-Station-Id}'), \
- expiry_time \
- LIMIT 1 \
- FOR UPDATE"
-
-# ## If you prefer to allocate a random IP address every time, i
-# ## use this query instead
-# allocate_find = "SELECT framedipaddress FROM ${ippool_table} \
-# WHERE pool_name = '%{control:Pool-Name}' \
-# AND expiry_time IS NULL \
-# ORDER BY RAND() \
-# LIMIT 1 \
-# FOR UPDATE"
-
-
-
-## If an IP could not be allocated, check to see if the pool exists or not
-## This allows the module to differentiate between a full pool and no pool
-## Note: If you are not running redundant pool modules this query may be
-## commented out to save running this query every time an ip is not allocated.
-pool_check = "SELECT id FROM ${ippool_table} \
- WHERE pool_name='%{control:Pool-Name}' LIMIT 1"
-
-
-## This is the final IP Allocation query, which saves the allocated ip details
-allocate_update = "UPDATE ${ippool_table} \
- SET nasipaddress = '%{NAS-IP-Address}', pool_key = '${pool_key}', \
- callingstationid = '%{Calling-Station-Id}', username = '%{User-Name}', \
- expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
- WHERE framedipaddress = '%I' AND expiry_time IS NULL"
-
-
-
-## This series of queries frees an IP number when an accounting
-## START record arrives
-start_update = "UPDATE ${ippool_table} \
- SET expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
- WHERE nasipaddress = '%{NAS-IP-Address}' AND pool_key = '${pool_key}' \
- AND username = '%{User-Name}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND framedipaddress = '%{Framed-IP-Address}'"
-
-## This series of queries frees an IP number when an accounting
-## STOP record arrives
-stop_clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, callingstationid = '', username = '', \
- expiry_time = NULL \
- WHERE nasipaddress = '%{Nas-IP-Address}' AND pool_key = '${pool_key}' \
- AND username = '%{User-Name}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND framedipaddress = '%{Framed-IP-Address}'"
-
-
-
-## This series of queries frees an IP number when an accounting
-## ALIVE record arrives
-alive_update = "UPDATE ${ippool_table} \
- SET expiry_time = NOW() + INTERVAL ${lease_duration} SECOND \
- WHERE nasipaddress = '%{Nas-IP-Address}' AND pool_key = '${pool_key}' \
- AND username = '%{User-Name}' \
- AND callingstationid = '%{Calling-Station-Id}' \
- AND framedipaddress = '%{Framed-IP-Address}'"
-
-
-
-## This series of queries frees the IP numbers allocate to a
-## NAS when an accounting ON record arrives
-on-clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, callingstationid = '', username = '', \
- expiry_time = NULL \
- WHERE nasipaddress = '%{Nas-IP-Address}'"
-
-## This series of queries frees the IP numbers allocate to a
-## NAS when an accounting OFF record arrives
-off-clear = "UPDATE ${ippool_table} \
- SET nasipaddress = '', pool_key = 0, callingstationid = '', username = '', \
- expiry_time = NULL \
- WHERE nasipaddress = '%{Nas-IP-Address}'"
+#
+# ippool/sqlite/queries.conf -- SQLite queries for rlm_sqlippool
+#
+# $Id$
+
+#
+# This series of queries allocates an IP address
+#
+#allocate_clear = "\
+# UPDATE ${ippool_table} \
+# SET \
+# nasipaddress = '', pool_key = 0, \
+# callingstationid = '', username = '', \
+# expiry_time = NULL \
+# WHERE pool_key = '${pool_key}'"
+
+#
+# This series of queries allocates an IP address
+# (Note: If your pool_key is set to Calling-Station-Id and not NAS-Port
+# then you may wish to delete the "AND nasipaddress = '%{Nas-IP-Address}'
+# from the WHERE clause)
+#
+allocate_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ username = '', \
+ expiry_time = NULL \
+ WHERE expiry_time <= datetime(strftime('%%s', 'now') - 1, 'unixepoch') \
+ AND nasipaddress = '%{Nas-IP-Address}'"
+
+#
+# The ORDER BY clause of this query tries to allocate the same IP-address
+# which user had last session...
+#
+allocate_find = "\
+ SELECT framedipaddress \
+ FROM ${ippool_table} \
+ WHERE pool_name = '%{control:Pool-Name}' \
+ AND (expiry_time < datetime('now') OR expiry_time IS NULL) \
+ ORDER BY \
+ (username <> '%{User-Name}'), \
+ (callingstationid <> '%{Calling-Station-Id}'), \
+ expiry_time \
+ LIMIT 1 \
+ FOR UPDATE"
+
+#
+# If you prefer to allocate a random IP address every time, i
+# use this query instead
+#
+
+#allocate_find = "\
+# SELECT framedipaddress \
+# FROM ${ippool_table} \
+# WHERE pool_name = '%{control:Pool-Name}' \
+# AND expiry_time IS NULL \
+# ORDER BY RAND() \
+# LIMIT 1 \
+# FOR UPDATE"
+
+#
+# If an IP could not be allocated, check to see if the pool exists or not
+# This allows the module to differentiate between a full pool and no pool
+# Note: If you are not running redundant pool modules this query may be
+# commented out to save running this query every time an ip is not allocated.
+#
+pool_check = "\
+ SELECT id \
+ FROM ${ippool_table} \
+ WHERE pool_name='%{control:Pool-Name}' \
+ LIMIT 1"
+
+#
+# This is the final IP Allocation query, which saves the allocated ip details
+#
+allocate_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '%{NAS-IP-Address}', \
+ pool_key = '${pool_key}', \
+ callingstationid = '%{Calling-Station-Id}', \
+ username = '%{User-Name}', \
+ expiry_time = datetime(strftime('%%s', 'now') + ${lease_duration}, 'unixepoch') \
+ WHERE framedipaddress = '%I' \
+ AND expiry_time IS NULL"
+
+#
+# This series of queries frees an IP number when an accounting START record arrives
+#
+start_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = datetime(strftime('%%s', 'now') + ${lease_duration}, 'unixepoch') \
+ WHERE nasipaddress = '%{NAS-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND framedipaddress = '%{Framed-IP-Address}'"
+
+#
+# This series of queries frees an IP number when an accounting STOP record arrives
+#
+stop_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ username = '', \
+ expiry_time = NULL \
+ WHERE nasipaddress = '%{Nas-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND framedipaddress = '%{Framed-IP-Address}'"
+
+#
+# This series of queries frees an IP number when an accounting
+# ALIVE record arrives
+#
+alive_update = "\
+ UPDATE ${ippool_table} \
+ SET \
+ expiry_time = datetime(strftime('%%s', 'now') + ${lease_duration}, 'unixepoch') \
+ WHERE nasipaddress = '%{Nas-IP-Address}' \
+ AND pool_key = '${pool_key}' \
+ AND username = '%{User-Name}' \
+ AND callingstationid = '%{Calling-Station-Id}' \
+ AND framedipaddress = '%{Framed-IP-Address}'"
+
+#
+# This series of queries frees the IP numbers allocate to a
+# NAS when an accounting ON record arrives
+#
+on_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ username = '', \
+ expiry_time = NULL \
+ WHERE nasipaddress = '%{Nas-IP-Address}'"
+
+#
+# This series of queries frees the IP numbers allocate to a
+# NAS when an accounting OFF record arrives
+#
+off_clear = "\
+ UPDATE ${ippool_table} \
+ SET \
+ nasipaddress = '', \
+ pool_key = 0, \
+ callingstationid = '', \
+ username = '', \
+ expiry_time = NULL \
+ WHERE nasipaddress = '%{Nas-IP-Address}'"
# -*- text -*-
-##
-## dialup.conf -- MSSQL configuration for default schema (schema.sql)
-##
-## $Id$
+#
+# main/mssql/queries.conf -- MSSQL configuration for default schema (schema.sql)
+#
+# $Id$
- # Safe characters list for sql queries. Everything else is replaced
- # with their mime-encoded equivalents.
- # The default list should be ok
- #safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"
+# Safe characters list for sql queries. Everything else is replaced
+# with their mime-encoded equivalents.
+# The default list should be ok
+#safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"
- #######################################################################
- # Query config: Username
- #######################################################################
- # This is the username that will get substituted, escaped, and added
- # as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used
- # below everywhere a username substitution is needed so you you can
- # be sure the username passed from the client is escaped properly.
- #
- # Uncomment the next line, if you want the sql_user_name to mean:
- #
- # Use Stripped-User-Name, if it's there.
- # Else use User-Name, if it's there,
- # Else use hard-coded string "none" as the user name.
- #sql_user_name = "%{%{Stripped-User-Name}:-%{User-Name:-none}}"
- #
- sql_user_name = "%{User-Name}"
+#######################################################################
+# Query config: Username
+#######################################################################
+# This is the username that will get substituted, escaped, and added
+# as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used
+# below everywhere a username substitution is needed so you you can
+# be sure the username passed from the client is escaped properly.
+#
+# Uncomment the next line, if you want the sql_user_name to mean:
+#
+# Use Stripped-User-Name, if it's there.
+# Else use User-Name, if it's there,
+# Else use hard-coded string "none" as the user name.
+#sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-none}}"
+#
+sql_user_name = "%{User-Name}"
+#######################################################################
+# Authorization Queries
+#######################################################################
+# These queries compare the check items for the user
+# in ${authcheck_table} and setup the reply items in
+# ${authreply_table}. You can use any query/tables
+# you want, but the return data for each row MUST
+# be in the following order:
+#
+# 0. Row ID (currently unused)
+# 1. UserName/GroupName
+# 2. Item Attr Name
+# 3. Item Attr Value
+# 4. Item Attr Operation
+#######################################################################
+# Query for case sensitive usernames was removed. Please contact with me,
+# if you know analog of STRCMP functions for MS SQL.
- #######################################################################
- # Authorization Queries
- #######################################################################
- # These queries compare the check items for the user
- # in ${authcheck_table} and setup the reply items in
- # ${authreply_table}. You can use any query/tables
- # you want, but the return data for each row MUST
- # be in the following order:
- #
- # 0. Row ID (currently unused)
- # 1. UserName/GroupName
- # 2. Item Attr Name
- # 3. Item Attr Value
- # 4. Item Attr Operation
- #######################################################################
- # Query for case sensitive usernames was removed. Please contact with me,
- # if you know analog of STRCMP functions for MS SQL.
+authorize_check_query = "\
+ SELECT id, UserName, Attribute, Value, op \
+ FROM ${authcheck_table} \
+ WHERE Username = '%{SQL-User-Name}' \
+ ORDER BY id"
- authorize_check_query = "SELECT id,UserName,Attribute,Value,op \
- FROM ${authcheck_table} \
- WHERE Username = '%{SQL-User-Name}' \
- ORDER BY id"
+authorize_reply_query = "\
+ SELECT id, UserName, Attribute, Value, op \
+ FROM ${authreply_table} \
+ WHERE Username = '%{SQL-User-Name}' \
+ ORDER BY id"
- authorize_reply_query = "SELECT id,UserName,Attribute,Value,op \
- FROM ${authreply_table} \
- WHERE Username = '%{SQL-User-Name}' \
- ORDER BY id"
+authorize_group_check_query = "\
+ SELECT \
+ ${groupcheck_table}.id,${groupcheck_table}.GroupName, \
+ ${groupcheck_table}.Attribute,${groupcheck_table}.Value, \
+ ${groupcheck_table}.op \
+ FROM ${groupcheck_table},${usergroup_table} \
+ WHERE ${usergroup_table}.Username = '%{SQL-User-Name}' \
+ AND ${usergroup_table}.GroupName = ${groupcheck_table}.GroupName \
+ ORDER BY ${groupcheck_table}.id"
- authorize_group_check_query = "SELECT ${groupcheck_table}.id,${groupcheck_table}.GroupName, \
- ${groupcheck_table}.Attribute,${groupcheck_table}.Value, \
- ${groupcheck_table}.op \
- FROM ${groupcheck_table},${usergroup_table} \
- WHERE ${usergroup_table}.Username = '%{SQL-User-Name}' \
- AND ${usergroup_table}.GroupName = ${groupcheck_table}.GroupName \
- ORDER BY ${groupcheck_table}.id"
- authorize_group_reply_query = "SELECT ${groupreply_table}.id,${groupreply_table}.GroupName, \
- ${groupreply_table}.Attribute,${groupreply_table}.Value, \
- ${groupreply_table}.op \
- FROM ${groupreply_table},${usergroup_table} \
- WHERE ${usergroup_table}.Username = '%{SQL-User-Name}' \
- AND ${usergroup_table}.GroupName = ${groupreply_table}.GroupName \
- ORDER BY ${groupreply_table}.id"
+authorize_group_reply_query = "\
+ SELECT \
+ ${groupreply_table}.id, ${groupreply_table}.GroupName, \
+ ${groupreply_table}.Attribute,${groupreply_table}.Value, \
+ ${groupreply_table}.op \
+ FROM ${groupreply_table},${usergroup_table} \
+ WHERE ${usergroup_table}.Username = '%{SQL-User-Name}' \
+ AND ${usergroup_table}.GroupName = ${groupreply_table}.GroupName \
+ ORDER BY ${groupreply_table}.id"
- group_membership_query = "SELECT groupname \
- FROM ${usergroup_table} \
- WHERE username = '%{SQL-User-Name}' \
- ORDER BY priority"
+group_membership_query = "\
+ SELECT groupname \
+ FROM ${usergroup_table} \
+ WHERE username = '%{SQL-User-Name}' \
+ ORDER BY priority"
- #######################################################################
- # Accounting and Post-Auth Queries
- #######################################################################
- # These queries insert/update accounting and authentication records.
- # The query to use is determined by the value of 'reference'.
- # This value is used as a configuration path and should resolve to one
- # or more 'query's. If reference points to multiple queries, and a query
- # fails, the next query is executed.
- #
- # Behaviour is identical to the old 1.x/2.x module, except we can now
- # fail between N queries, and query selection can be based on any
- # combination of attributes, or custom 'Acct-Status-Type' values.
- #######################################################################
- accounting {
- reference = "%{tolower:type.%{Acct-Status-Type}.query}"
+#######################################################################
+# Accounting and Post-Auth Queries
+#######################################################################
+# These queries insert/update accounting and authentication records.
+# The query to use is determined by the value of 'reference'.
+# This value is used as a configuration path and should resolve to one
+# or more 'query's. If reference points to multiple queries, and a query
+# fails, the next query is executed.
+#
+# Behaviour is identical to the old 1.x/2.x module, except we can now
+# fail between N queries, and query selection can be based on any
+# combination of attributes, or custom 'Acct-Status-Type' values.
+#######################################################################
+accounting {
+ reference = "%{tolower:type.%{Acct-Status-Type}.query}"
- # Write SQL queries to a logfile. This is potentially useful for bulk inserts
- # when used with the rlm_sql_null driver.
-# logfile = ${logdir}/accounting.sql
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
+# logfile = ${logdir}/accounting.sql
- type {
- accounting-on {
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- AcctStopTime='%S', \
- AcctSessionTime=unix_timestamp('%S') - \
- unix_timestamp(AcctStartTime), \
- AcctTerminateCause='%{Acct-Terminate-Cause}', \
- AcctStopDelay = %{Acct-Delay-Time:-0} \
- WHERE AcctStopTime = 0 \
- AND NASIPAddress = '%{NAS-IP-Address}' \
- AND AcctStartTime <= '%S'"
- }
+ type {
+ accounting-on {
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctStopTime='%S', \
+ AcctSessionTime=unix_timestamp('%S') - \
+ unix_timestamp(AcctStartTime), \
+ AcctTerminateCause='%{%{Acct-Terminate-Cause}:-NAS-Reboot}', \
+ AcctStopDelay = %{%{Acct-Delay-Time}:-0} \
+ WHERE AcctStopTime = 0 \
+ AND NASIPAddress = '%{NAS-IP-Address}' \
+ AND AcctStartTime <= '%S'"
+ }
- accounting-off {
- query = "${..accounting-on.query}"
- }
+ accounting-off {
+ query = "${..accounting-on.query}"
+ }
- start {
- query = "\
- INSERT INTO ${....acct_table1} \
- (AcctSessionId, AcctUniqueId, UserName, \
- Realm, NASIPAddress, NASPort, \
- NASPortType, AcctStartTime, AcctSessionTime, \
- AcctAuthentic, ConnectInfo_start, ConnectInfo_stop, \
- AcctInputOctets, AcctOutputOctets, CalledStationId, \
- CallingStationId, AcctTerminateCause, ServiceType, \
- FramedProtocol, FramedIPAddress, AcctStartDelay, \
- AcctStopDelay, XAscendSessionSvrKey) \
- VALUES(\
- '%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{NAS-Port-Id}', \
- '%{NAS-Port-Type}', \
- '%S', \
- '0', \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- '', \
- '0', \
- '0', \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '%{Acct-Delay-Time}', \
- '0', \
- '%{X-Ascend-Session-Svr-Key}')"
+ start {
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (AcctSessionId, AcctUniqueId, UserName, \
+ Realm, NASIPAddress, NASPort, \
+ NASPortType, AcctStartTime, AcctSessionTime, \
+ AcctAuthentic, ConnectInfo_start, ConnectInfo_stop, \
+ AcctInputOctets, AcctOutputOctets, CalledStationId, \
+ CallingStationId, AcctTerminateCause, ServiceType, \
+ FramedProtocol, FramedIPAddress, AcctStartDelay, \
+ AcctStopDelay, XAscendSessionSvrKey) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port-Id}', \
+ '%{NAS-Port-Type}', \
+ '%S', \
+ '0', \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ '0', \
+ '0', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Acct-Delay-Time}', \
+ '0', \
+ '%{X-Ascend-Session-Svr-Key}')"
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- AcctStartTime = '%S', \
- AcctStartDelay = '%{Acct-Delay-Time:-0}', \
- ConnectInfo_start = '%{Connect-Info}' \
- WHERE AcctSessionId = '%{Acct-Session-Id}' \
- AND UserName = '%{SQL-User-Name}' \
- AND NASIPAddress = '%{NAS-IP-Address}' \
- AND AcctStopTime = 0"
- }
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctStartTime = '%S', \
+ AcctStartDelay = '%{%{Acct-Delay-Time}:-0}', \
+ ConnectInfo_start = '%{Connect-Info}' \
+ WHERE AcctSessionId = '%{Acct-Session-Id}' \
+ AND UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{NAS-IP-Address}' \
+ AND AcctStopTime = 0"
+ }
- interim-update {
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- FramedIPAddress = '%{Framed-IP-Address}' \
- WHERE AcctSessionId = '%{Acct-Session-Id}' \
- AND UserName = '%{SQL-User-Name}' \
- AND NASIPAddress= '%{NAS-IP-Address}' \
- AND AcctStopTime = 0"
+ interim-update {
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ FramedIPAddress = '%{Framed-IP-Address}' \
+ WHERE AcctSessionId = '%{Acct-Session-Id}' \
+ AND UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress= '%{NAS-IP-Address}' \
+ AND AcctStopTime = 0"
- query = "\
- INSERT INTO ${....acct_table1} \
- (AcctSessionId, AcctUniqueId, UserName, \
- Realm, NASIPAddress, NASPort, \
- NASPortType, AcctSessionTime, AcctAuthentic, \
- ConnectInfo_start, AcctInputOctets, AcctOutputOctets, \
- CalledStationId, CallingStationId, ServiceType, \
- FramedProtocol, FramedIPAddress, AcctStartDelay, \
- XAscendSessionSvrKey) \
- VALUES(\
- '%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{NAS-Port-Id}', \
- '%{NAS-Port-Type}', \
- '%{Acct-Session-Time}', \
- '%{Acct-Authentic}', \
- '', \
- '%{Acct-Input-Octets}', \
- '%{Acct-Output-Octets}', \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '0', \
- '%{X-Ascend-Session-Svr-Key}')"
- }
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (AcctSessionId, AcctUniqueId, UserName, \
+ Realm, NASIPAddress, NASPort, \
+ NASPortType, AcctSessionTime, AcctAuthentic, \
+ ConnectInfo_start, AcctInputOctets, AcctOutputOctets, \
+ CalledStationId, CallingStationId, ServiceType, \
+ FramedProtocol, FramedIPAddress, AcctStartDelay, \
+ XAscendSessionSvrKey) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port-Id}', \
+ '%{NAS-Port-Type}', \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', \
+ '', \
+ '%{Acct-Input-Octets}', \
+ '%{Acct-Output-Octets}', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '0', \
+ '%{X-Ascend-Session-Svr-Key}')"
+ }
- stop {
- query = "\
- UPDATE ${....acct_table2} \
- SET \
- AcctStopTime = '%S', \
- AcctSessionTime = '%{Acct-Session-Time}', \
- AcctInputOctets = '%{Acct-Input-Octets}', \
- AcctOutputOctets = '%{Acct-Output-Octets}', \
- AcctTerminateCause = '%{Acct-Terminate-Cause}', \
- AcctStopDelay = '%{Acct-Delay-Time:-0}', \
- ConnectInfo_stop = '%{Connect-Info}' \
- WHERE AcctSessionId = '%{Acct-Session-Id}' \
- AND UserName = '%{SQL-User-Name}' \
- AND NASIPAddress = '%{NAS-IP-Address}' \
- AND AcctStopTime = 0"
+ stop {
+ query = "\
+ UPDATE ${....acct_table2} \
+ SET \
+ AcctStopTime = '%S', \
+ AcctSessionTime = '%{Acct-Session-Time}', \
+ AcctInputOctets = '%{Acct-Input-Octets}', \
+ AcctOutputOctets = '%{Acct-Output-Octets}', \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ AcctStopDelay = '%{%{Acct-Delay-Time}:-0}', \
+ ConnectInfo_stop = '%{Connect-Info}' \
+ WHERE AcctSessionId = '%{Acct-Session-Id}' \
+ AND UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{NAS-IP-Address}' \
+ AND AcctStopTime = 0"
- query = "\
- INSERT into ${....acct_table2} \
- (AcctSessionId, AcctUniqueId, UserName, \
- Realm, NASIPAddress, NASPort, \
- NASPortType, AcctStopTime, AcctSessionTime, \
- AcctAuthentic, ConnectInfo_start, ConnectInfo_stop, \
- AcctInputOctets, AcctOutputOctets, CalledStationId, \
- CallingStationId, AcctTerminateCause, ServiceType, \
- FramedProtocol, FramedIPAddress, AcctStartDelay, \
- AcctStopDelay) \
- VALUES(\
- '%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{NAS-Port-Id}', \
- '%{NAS-Port-Type}', \
- '%S', \
- '%{Acct-Session-Time}', \
- '%{Acct-Authentic}', \
- '', \
- '%{Connect-Info}', \
- '%{Acct-Input-Octets}', \
- '%{Acct-Output-Octets}', \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Acct-Terminate-Cause}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '0', \
- '%{Acct-Delay-Time:-0}')"
- }
+ query = "\
+ INSERT into ${....acct_table2} \
+ (AcctSessionId, AcctUniqueId, UserName, \
+ Realm, NASIPAddress, NASPort, \
+ NASPortType, AcctStopTime, AcctSessionTime, \
+ AcctAuthentic, ConnectInfo_start, ConnectInfo_stop, \
+ AcctInputOctets, AcctOutputOctets, CalledStationId, \
+ CallingStationId, AcctTerminateCause, ServiceType, \
+ FramedProtocol, FramedIPAddress, AcctStartDelay, \
+ AcctStopDelay) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port-Id}', \
+ '%{NAS-Port-Type}', \
+ '%S', \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', \
+ '', \
+ '%{Connect-Info}', \
+ '%{Acct-Input-Octets}', \
+ '%{Acct-Output-Octets}', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Acct-Terminate-Cause}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '0', \
+ '%{%{Acct-Delay-Time}:-0}')"
}
}
+}
- post-auth {
- # Write SQL queries to a logfile. This is potentially useful for bulk inserts
- # when used with the rlm_sql_null driver.
-# logfile = ${logdir}/post-auth.sql
- }
+post-auth {
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
+# logfile = ${logdir}/post-auth.sql
+}
/****** Object: Table [radusergroup] Script Date: 16.04.08 19:44:11 ******/
CREATE TABLE [radpostauth] (
- [id] [int] IDENTITY (1, 1) NOT NULL ,
- [userName] [varchar] (64) NOT NULL ,
- [pass] [varchar] (64) NOT NULL ,
- [reply] [varchar] (32) NOT NULL ,
- [authdate] [datetime] NOT NULL
+ [id] [int] IDENTITY (1, 1) NOT NULL ,
+ [userName] [varchar] (64) NOT NULL ,
+ [pass] [varchar] (64) NOT NULL ,
+ [reply] [varchar] (32) NOT NULL ,
+ [authdate] [datetime] NOT NULL
)
GO
GO
ALTER TABLE [radpostauth] WITH NOCHECK ADD
- CONSTRAINT [DF_radpostauth_userName] DEFAULT ('') FOR [userName],
- CONSTRAINT [DF_radpostauth_pass] DEFAULT ('') FOR [pass],
- CONSTRAINT [DF_radpostauth_reply] DEFAULT ('') FOR [reply],
- CONSTRAINT [DF_radpostauth_authdate] DEFAULT (getdate()) FOR [authdate],
- CONSTRAINT [PK_radpostauth] PRIMARY KEY NONCLUSTERED
- (
- [id]
- ) ON [PRIMARY]
+ CONSTRAINT [DF_radpostauth_userName] DEFAULT ('') FOR [userName],
+ CONSTRAINT [DF_radpostauth_pass] DEFAULT ('') FOR [pass],
+ CONSTRAINT [DF_radpostauth_reply] DEFAULT ('') FOR [reply],
+ CONSTRAINT [DF_radpostauth_authdate] DEFAULT (getdate()) FOR [authdate],
+ CONSTRAINT [PK_radpostauth] PRIMARY KEY NONCLUSTERED
+ (
+ [id]
+ ) ON [PRIMARY]
GO
CREATE INDEX [UserName] ON [radacct]([UserName]) ON [PRIMARY]
# -*- text -*-
-##
-## dialup.conf -- MySQL configuration for default schema (schema.sql)
-##
-## $Id$
-
- # Safe characters list for sql queries. Everything else is replaced
- # with their mime-encoded equivalents.
- # The default list should be ok
- #safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"
-
- #######################################################################
- # Connection config
- #######################################################################
- # The character set is not configurable. The default character set of
- # the mysql client library is used. To control the character set,
- # create/edit my.cnf (typically in /etc/mysql/my.cnf or /etc/my.cnf)
- # and enter
- # [client]
- # default-character-set = utf8
- #
-
- #######################################################################
- # Query config: Username
- #######################################################################
- # This is the username that will get substituted, escaped, and added
- # as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used below
- # everywhere a username substitution is needed so you you can be sure
- # the username passed from the client is escaped properly.
- #
- # Uncomment the next line, if you want the sql_user_name to mean:
- #
- # Use Stripped-User-Name, if it's there.
- # Else use User-Name, if it's there,
- # Else use hard-coded string "DEFAULT" as the user name.
- #sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}}"
- #
- sql_user_name = "%{User-Name}"
-
- #######################################################################
- # Default profile
- #######################################################################
- # This is the default profile. It is found in SQL by group membership.
- # That means that this profile must be a member of at least one group
- # which will contain the corresponding check and reply items.
- # This profile will be queried in the authorize section for every user.
- # The point is to assign all users a default profile without having to
- # manually add each one to a group that will contain the profile.
- # The SQL module will also honor the User-Profile attribute. This
- # attribute can be set anywhere in the authorize section (ie the users
- # file). It is found exactly as the default profile is found.
- # If it is set then it will *overwrite* the default profile setting.
- # The idea is to select profiles based on checks on the incoming packets,
- # not on user group membership. For example:
- # -- users file --
- # DEFAULT Service-Type == Outbound-User, User-Profile := "outbound"
- # DEFAULT Service-Type == Framed-User, User-Profile := "framed"
- #
- # By default the default_user_profile is not set
- #
- #default_user_profile = "DEFAULT"
-
- #######################################################################
- # NAS Query
- #######################################################################
- # This query retrieves the radius clients
- #
- # 0. Row ID (currently unused)
- # 1. Name (or IP address)
- # 2. Shortname
- # 3. Type
- # 4. Secret
- # 5. Server
- #######################################################################
-
- client_query = "SELECT id, nasname, shortname, type, secret, server FROM ${client_table}"
-
- #######################################################################
- # Authorization Queries
- #######################################################################
- # These queries compare the check items for the user
- # in ${authcheck_table} and setup the reply items in
- # ${authreply_table}. You can use any query/tables
- # you want, but the return data for each row MUST
- # be in the following order:
- #
- # 0. Row ID (currently unused)
- # 1. UserName/GroupName
- # 2. Item Attr Name
- # 3. Item Attr Value
- # 4. Item Attr Operation
- #######################################################################
- # Use these for case sensitive usernames.
-# authorize_check_query = "\
+#
+# main/mysql/queries.conf-- MySQL configuration for default schema (schema.sql)
+#
+# $Id$
+
+# Safe characters list for sql queries. Everything else is replaced
+# with their mime-encoded equivalents.
+# The default list should be ok
+#safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"
+
+#######################################################################
+# Connection config
+#######################################################################
+# The character set is not configurable. The default character set of
+# the mysql client library is used. To control the character set,
+# create/edit my.cnf (typically in /etc/mysql/my.cnf or /etc/my.cnf)
+# and enter
+# [client]
+# default-character-set = utf8
+#
+
+#######################################################################
+# Query config: Username
+#######################################################################
+# This is the username that will get substituted, escaped, and added
+# as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used below
+# everywhere a username substitution is needed so you you can be sure
+# the username passed from the client is escaped properly.
+#
+# Uncomment the next line, if you want the sql_user_name to mean:
+#
+# Use Stripped-User-Name, if it's there.
+# Else use User-Name, if it's there,
+# Else use hard-coded string "DEFAULT" as the user name.
+#sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}}"
+#
+sql_user_name = "%{User-Name}"
+
+#######################################################################
+# Default profile
+#######################################################################
+# This is the default profile. It is found in SQL by group membership.
+# That means that this profile must be a member of at least one group
+# which will contain the corresponding check and reply items.
+# This profile will be queried in the authorize section for every user.
+# The point is to assign all users a default profile without having to
+# manually add each one to a group that will contain the profile.
+# The SQL module will also honor the User-Profile attribute. This
+# attribute can be set anywhere in the authorize section (ie the users
+# file). It is found exactly as the default profile is found.
+# If it is set then it will *overwrite* the default profile setting.
+# The idea is to select profiles based on checks on the incoming packets,
+# not on user group membership. For example:
+# -- users file --
+# DEFAULT Service-Type == Outbound-User, User-Profile := "outbound"
+# DEFAULT Service-Type == Framed-User, User-Profile := "framed"
+#
+# By default the default_user_profile is not set
+#
+#default_user_profile = "DEFAULT"
+
+#######################################################################
+# NAS Query
+#######################################################################
+# This query retrieves the radius clients
+#
+# 0. Row ID (currently unused)
+# 1. Name (or IP address)
+# 2. Shortname
+# 3. Type
+# 4. Secret
+# 5. Server
+#######################################################################
+
+client_query = "\
+ SELECT id, nasname, shortname, type, secret, server \
+ FROM ${client_table}"
+
+#######################################################################
+# Authorization Queries
+#######################################################################
+# These queries compare the check items for the user
+# in ${authcheck_table} and setup the reply items in
+# ${authreply_table}. You can use any query/tables
+# you want, but the return data for each row MUST
+# be in the following order:
+#
+# 0. Row ID (currently unused)
+# 1. UserName/GroupName
+# 2. Item Attr Name
+# 3. Item Attr Value
+# 4. Item Attr Operation
+#######################################################################
+# Use these for case sensitive usernames.
+
+#authorize_check_query = "\
# SELECT id, username, attribute, value, op \
# FROM ${authcheck_table} \
# WHERE username = BINARY '%{SQL-User-Name}' \
# ORDER BY id"
-# authorize_reply_query = "\
+#authorize_reply_query = "\
# SELECT id, username, attribute, value, op \
# FROM ${authreply_table} \
# WHERE username = BINARY '%{SQL-User-Name}' \
# ORDER BY id"
- # The default queries are case insensitive. (for compatibility with
- # older versions of FreeRADIUS)
- authorize_check_query = "\
+#
+# The default queries are case insensitive. (for compatibility with
+# older versions of FreeRADIUS)
+#
+authorize_check_query = "\
SELECT id, username, attribute, value, op \
FROM ${authcheck_table} \
WHERE username = '%{SQL-User-Name}' \
ORDER BY id"
- authorize_reply_query = "\
+authorize_reply_query = "\
SELECT id, username, attribute, value, op \
FROM ${authreply_table} \
WHERE username = '%{SQL-User-Name}' \
ORDER BY id"
- # Use these for case sensitive usernames.
-# group_membership_query = "\
+#
+# Use these for case sensitive usernames.
+#
+group_membership_query = "\
# SELECT groupname \
# FROM ${usergroup_table} \
# WHERE username = BINARY '%{SQL-User-Name}' \
# ORDER BY priority"
- group_membership_query = "\
+group_membership_query = "\
SELECT groupname \
FROM ${usergroup_table} \
WHERE username = '%{SQL-User-Name}' \
ORDER BY priority"
- authorize_group_check_query = "\
+authorize_group_check_query = "\
SELECT id, groupname, attribute, \
Value, op \
FROM ${groupcheck_table} \
WHERE groupname = '%{Sql-Group}' \
ORDER BY id"
- authorize_group_reply_query = "\
+authorize_group_reply_query = "\
SELECT id, groupname, attribute, \
value, op \
FROM ${groupreply_table} \
WHERE groupname = '%{Sql-Group}' \
ORDER BY id"
- #######################################################################
- # Simultaneous Use Checking Queries
- #######################################################################
- # simul_count_query - query for the number of current connections
- # - If this is not defined, no simultaneouls use checking
- # - will be performed by this module instance
- # simul_verify_query - query to return details of current connections
- # for verification
- # - Leave blank or commented out to disable verification step
- # - Note that the returned field order should not be changed.
- #######################################################################
-
- # Uncomment simul_count_query to enable simultaneous use checking
-# simul_count_query = "\
+#######################################################################
+# Simultaneous Use Checking Queries
+#######################################################################
+# simul_count_query - query for the number of current connections
+# - If this is not defined, no simultaneouls use checking
+# - will be performed by this module instance
+# simul_verify_query - query to return details of current connections
+# for verification
+# - Leave blank or commented out to disable verification step
+# - Note that the returned field order should not be changed.
+#######################################################################
+
+#
+# Uncomment simul_count_query to enable simultaneous use checking
+#
+#simul_count_query = "\
# SELECT COUNT(*) \
# FROM ${acct_table1} \
# WHERE username = '%{SQL-User-Name}' \
# AND acctstoptime IS NULL"
- simul_verify_query = "\
- SELECT radacctid, acctsessionid, username, \
- nasipaddress, nasportid, framedipaddress, \
- callingstationid, framedprotocol \
+simul_verify_query = "\
+ SELECT \
+ radacctid, acctsessionid, username, nasipaddress, nasportid, framedipaddress, \
+ callingstationid, framedprotocol \
FROM ${acct_table1} \
WHERE username = '%{SQL-User-Name}' \
AND acctstoptime IS NULL"
- #######################################################################
- # Accounting and Post-Auth Queries
- #######################################################################
- # These queries insert/update accounting and authentication records.
- # The query to use is determined by the value of 'reference'.
- # This value is used as a configuration path and should resolve to one
- # or more 'query's. If reference points to multiple queries, and a query
- # fails, the next query is executed.
- #
- # Behaviour is identical to the old 1.x/2.x module, except we can now
- # fail between N queries, and query selection can be based on any
- # combination of attributes, or custom 'Acct-Status-Type' values.
- #######################################################################
- accounting {
- reference = "%{tolower:type.%{Acct-Status-Type}.query}"
-
- # Write SQL queries to a logfile. This is potentially useful for bulk inserts
- # when used with the rlm_sql_null driver.
-# logfile = ${logdir}/accounting.sql
-
- column_list = "\
- acctsessionid, acctuniqueid, username, \
- realm, nasipaddress, nasportid, \
- nasporttype, acctstarttime, acctupdatetime, \
- acctstoptime, acctsessiontime, acctauthentic, \
- connectinfo_start, connectinfo_stop, acctinputoctets, \
- acctoutputoctets, calledstationid, callingstationid, \
- acctterminatecause, servicetype, framedprotocol, \
- framedipaddress"
-
- type {
- accounting-on {
- #
- # Bulk terminate all sessions associated with a given NAS
- #
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- acctstoptime = FROM_UNIXTIME(\
- %{integer:Event-Timestamp}), \
- acctsessiontime = '%{integer:Event-Timestamp}' \
- - UNIX_TIMESTAMP(acctstarttime), \
- acctterminatecause = '%{Acct-Terminate-Cause}' \
- WHERE acctstoptime IS NULL \
- AND nasipaddress = '%{NAS-IP-Address}' \
- AND acctstarttime <= FROM_UNIXTIME(\
- %{integer:Event-Timestamp})"
- }
-
- accounting-off {
- query = "${..accounting-on.query}"
- }
-
- start {
- #
- # Insert a new record into the sessions table
- #
- query = "\
- INSERT INTO ${....acct_table1} \
- (${...column_list}) \
- VALUES \
- ('%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{NAS-Port}', \
- '%{NAS-Port-Type}', \
- FROM_UNIXTIME(%{integer:Event-Timestamp}), \
- FROM_UNIXTIME(%{integer:Event-Timestamp}), \
- NULL, \
- '0', \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- '', \
- '0', \
- '0', \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}')"
-
- #
- # Key constraints prevented us from inserting a new session,
- # use the alternate query to update an existing session.
- #
- query = "\
- UPDATE ${....acct_table1} SET \
- acctstarttime = FROM_UNIXTIME(\
- %{integer:Event-Timestamp}), \
- acctupdatetime = FROM_UNIXTIME(\
- %{integer:Event-Timestamp}), \
- connectinfo_start = '%{Connect-Info}' \
- WHERE acctsessionid = '%{Acct-Session-Id}' \
- AND username = '%{SQL-User-Name}' \
- AND nasipaddress = '%{NAS-IP-Address}'"
- }
-
- interim-update {
- #
- # Update an existing session and calculate the interval
- # between the last data we received for the session and this
- # update. This can be used to find stale sessions.
- #
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- acctupdatetime = (\
- @acctupdatetime_old:=acctupdatetime), \
- acctupdatetime = FROM_UNIXTIME(\
- %{integer:Event-Timestamp}), \
- acctinterval = %{integer:Event-Timestamp} - \
- UNIX_TIMESTAMP(@acctupdatetime_old), \
- framedipaddress = '%{Framed-IP-Address}', \
- acctsessiontime = '%{Acct-Session-Time}', \
- acctinputoctets = '%{%{Acct-Input-Gigawords}:-0}' \
- << 32 | '%{%{Acct-Input-Octets}:-0}', \
- acctoutputoctets = '%{%{Acct-Output-Gigawords}:-0}' \
- << 32 | '%{%{Acct-Output-Octets}:-0}' \
- WHERE acctsessionid = '%{Acct-Session-Id}' \
- AND username = '%{SQL-User-Name}' \
- AND nasipaddress = '%{NAS-IP-Address}'"
-
- #
- # The update condition matched no existing sessions. Use
- # the values provided in the update to create a new session.
- #
- query = "\
- INSERT INTO ${....acct_table1} \
- (${...column_list}) \
- VALUES \
- ('%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{NAS-Port}', \
- '%{NAS-Port-Type}', \
- FROM_UNIXTIME(%{integer:Event-Timestamp} - \
- %{%{Acct-Session-Time}:-0}), \
- FROM_UNIXTIME(%{integer:Event-Timestamp}), \
- NULL, \
- '%{Acct-Session-Time}', \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- '', \
- '%{%{Acct-Input-Gigawords}:-0}' << 32 | \
- '%{%{Acct-Input-Octets}:-0}', \
- '%{%{Acct-Output-Gigawords}:-0}' << 32 | \
- '%{%{Acct-Output-Octets}:-0}', \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}')"
- }
-
- stop {
- #
- # Session has terminated, update the stop time and statistics.
- #
- query = "\
- UPDATE ${....acct_table2} SET \
- acctstoptime = FROM_UNIXTIME(\
- %{integer:Event-Timestamp}), \
- acctsessiontime = '%{Acct-Session-Time}', \
- acctinputoctets = '%{%{Acct-Input-Gigawords}:-0}' \
- << 32 | '%{%{Acct-Input-Octets}:-0}', \
- acctoutputoctets = '%{%{Acct-Output-Gigawords}:-0}' \
- << 32 | '%{%{Acct-Output-Octets}:-0}', \
- acctterminatecause = '%{Acct-Terminate-Cause}', \
- connectinfo_stop = '%{Connect-Info}' \
- WHERE acctsessionid = '%{Acct-Session-Id}' \
- AND username = '%{SQL-User-Name}' \
- AND nasipaddress = '%{NAS-IP-Address}'"
-
- #
- # The update condition matched no existing sessions. Use
- # the values provided in the update to create a new session.
- #
- query = "\
- INSERT INTO ${....acct_table2} \
- (${...column_list}) \
- VALUES \
- ('%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{NAS-Port}', \
- '%{NAS-Port-Type}', \
- FROM_UNIXTIME(%{integer:Event-Timestamp} - \
- %{%{Acct-Session-Time}:-0}), \
- FROM_UNIXTIME(%{integer:Event-Timestamp}), \
- FROM_UNIXTIME(%{integer:Event-Timestamp}), \
- '%{Acct-Session-Time}', \
- '%{Acct-Authentic}', '', \
- '%{Connect-Info}', \
- '%{%{Acct-Input-Gigawords}:-0}' << 32 | \
- '%{%{Acct-Input-Octets}:-0}', \
- '%{%{Acct-Output-Gigawords}:-0}' << 32 | \
- '%{%{Acct-Output-Octets}:-0}', \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Acct-Terminate-Cause}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}')"
- }
+#######################################################################
+# Accounting and Post-Auth Queries
+#######################################################################
+# These queries insert/update accounting and authentication records.
+# The query to use is determined by the value of 'reference'.
+# This value is used as a configuration path and should resolve to one
+# or more 'query's. If reference points to multiple queries, and a query
+# fails, the next query is executed.
+#
+# Behaviour is identical to the old 1.x/2.x module, except we can now
+# fail between N queries, and query selection can be based on any
+# combination of attributes, or custom 'Acct-Status-Type' values.
+#######################################################################
+accounting {
+ reference = "%{tolower:type.%{Acct-Status-Type}.query}"
+
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
+# logfile = ${logdir}/accounting.sql
+
+ column_list = "\
+ acctsessionid, acctuniqueid, username, \
+ realm, nasipaddress, nasportid, \
+ nasporttype, acctstarttime, acctupdatetime, \
+ acctstoptime, acctsessiontime, acctauthentic, \
+ connectinfo_start, connectinfo_stop, acctinputoctets, \
+ acctoutputoctets, calledstationid, callingstationid, \
+ acctterminatecause, servicetype, framedprotocol, \
+ framedipaddress"
+
+ type {
+ accounting-on {
+ #
+ # Bulk terminate all sessions associated with a given NAS
+ #
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ acctstoptime = FROM_UNIXTIME(\
+ %{integer:Event-Timestamp}), \
+ acctsessiontime = '%{integer:Event-Timestamp}' \
+ - UNIX_TIMESTAMP(acctstarttime), \
+ acctterminatecause = '%{%{Acct-Terminate-Cause}:-NAS-Reboot}' \
+ WHERE acctstoptime IS NULL \
+ AND nasipaddress = '%{NAS-IP-Address}' \
+ AND acctstarttime <= FROM_UNIXTIME(\
+ %{integer:Event-Timestamp})"
}
- }
- #######################################################################
- # Authentication Logging Queries
- #######################################################################
- # postauth_query - Insert some info after authentication
- #######################################################################
-
- post-auth {
- # Write SQL queries to a logfile. This is potentially useful for bulk inserts
- # when used with the rlm_sql_null driver.
-# logfile = ${logdir}/post-auth.sql
-
- query = "\
- INSERT INTO ${..postauth_table} \
- (username, pass, reply, authdate) \
- VALUES ( \
- '%{SQL-User-Name}', \
- '%{%{User-Password}:-%{Chap-Password}}', \
- '%{reply:Packet-Type}', \
- '%S')"
+ accounting-off {
+ query = "${..accounting-on.query}"
+ }
+
+ start {
+ #
+ # Insert a new record into the sessions table
+ #
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (${...column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ FROM_UNIXTIME(%{integer:Event-Timestamp}), \
+ FROM_UNIXTIME(%{integer:Event-Timestamp}), \
+ NULL, \
+ '0', \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ '0', \
+ '0', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}')"
+
+ #
+ # Key constraints prevented us from inserting a new session,
+ # use the alternate query to update an existing session.
+ #
+ query = "\
+ UPDATE ${....acct_table1} SET \
+ acctstarttime = FROM_UNIXTIME(%{integer:Event-Timestamp}), \
+ acctupdatetime = FROM_UNIXTIME(%{integer:Event-Timestamp}), \
+ connectinfo_start = '%{Connect-Info}' \
+ WHERE acctsessionid = '%{Acct-Session-Id}' \
+ AND username = '%{SQL-User-Name}' \
+ AND nasipaddress = '%{NAS-IP-Address}'"
+ }
+
+ interim-update {
+ #
+ # Update an existing session and calculate the interval
+ # between the last data we received for the session and this
+ # update. This can be used to find stale sessions.
+ #
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ acctupdatetime = (@acctupdatetime_old:=acctupdatetime), \
+ acctupdatetime = FROM_UNIXTIME(\
+ %{integer:Event-Timestamp}), \
+ acctinterval = %{integer:Event-Timestamp} - \
+ UNIX_TIMESTAMP(@acctupdatetime_old), \
+ framedipaddress = '%{Framed-IP-Address}', \
+ acctsessiontime = '%{Acct-Session-Time}', \
+ acctinputoctets = '%{%{Acct-Input-Gigawords}:-0}' \
+ << 32 | '%{%{Acct-Input-Octets}:-0}', \
+ acctoutputoctets = '%{%{Acct-Output-Gigawords}:-0}' \
+ << 32 | '%{%{Acct-Output-Octets}:-0}' \
+ WHERE acctsessionid = '%{Acct-Session-Id}' \
+ AND username = '%{SQL-User-Name}' \
+ AND nasipaddress = '%{NAS-IP-Address}'"
+
+ #
+ # The update condition matched no existing sessions. Use
+ # the values provided in the update to create a new session.
+ #
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (${...column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ FROM_UNIXTIME(%{integer:Event-Timestamp} - \
+ %{%{Acct-Session-Time}:-0}), \
+ FROM_UNIXTIME(%{integer:Event-Timestamp}), \
+ NULL, \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ '%{%{Acct-Input-Gigawords}:-0}' << 32 | \
+ '%{%{Acct-Input-Octets}:-0}', \
+ '%{%{Acct-Output-Gigawords}:-0}' << 32 | \
+ '%{%{Acct-Output-Octets}:-0}', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}')"
+ }
+
+ stop {
+ #
+ # Session has terminated, update the stop time and statistics.
+ #
+ query = "\
+ UPDATE ${....acct_table2} SET \
+ acctstoptime = FROM_UNIXTIME(\
+ %{integer:Event-Timestamp}), \
+ acctsessiontime = '%{Acct-Session-Time}', \
+ acctinputoctets = '%{%{Acct-Input-Gigawords}:-0}' \
+ << 32 | '%{%{Acct-Input-Octets}:-0}', \
+ acctoutputoctets = '%{%{Acct-Output-Gigawords}:-0}' \
+ << 32 | '%{%{Acct-Output-Octets}:-0}', \
+ acctterminatecause = '%{Acct-Terminate-Cause}', \
+ connectinfo_stop = '%{Connect-Info}' \
+ WHERE acctsessionid = '%{Acct-Session-Id}' \
+ AND username = '%{SQL-User-Name}' \
+ AND nasipaddress = '%{NAS-IP-Address}'"
+
+ #
+ # The update condition matched no existing sessions. Use
+ # the values provided in the update to create a new session.
+ #
+ query = "\
+ INSERT INTO ${....acct_table2} \
+ (${...column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ FROM_UNIXTIME(%{integer:Event-Timestamp} - \
+ %{%{Acct-Session-Time}:-0}), \
+ FROM_UNIXTIME(%{integer:Event-Timestamp}), \
+ FROM_UNIXTIME(%{integer:Event-Timestamp}), \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', '', \
+ '%{Connect-Info}', \
+ '%{%{Acct-Input-Gigawords}:-0}' << 32 | \
+ '%{%{Acct-Input-Octets}:-0}', \
+ '%{%{Acct-Output-Gigawords}:-0}' << 32 | \
+ '%{%{Acct-Output-Octets}:-0}', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Acct-Terminate-Cause}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}')"
+ }
}
+}
+
+#######################################################################
+# Authentication Logging Queries
+#######################################################################
+# postauth_query - Insert some info after authentication
+#######################################################################
+
+post-auth {
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
+# logfile = ${logdir}/post-auth.sql
+
+ query = "\
+ INSERT INTO ${..postauth_table} \
+ (username, pass, reply, authdate) \
+ VALUES ( \
+ '%{SQL-User-Name}', \
+ '%{%{User-Password}:-%{Chap-Password}}', \
+ '%{reply:Packet-Type}', \
+ '%S')"
+}
acctupdatetime datetime NULL default NULL,
acctstoptime datetime NULL default NULL,
acctinterval int(12) default NULL,
- acctsessiontime unsigned int(12) default NULL,
+ acctsessiontime int(12) unsigned default NULL,
acctauthentic varchar(32) default NULL,
connectinfo_start varchar(50) default NULL,
connectinfo_stop varchar(50) default NULL,
# -*- text -*-
-##
-## dialup.conf -- Oracle configuration for default schema (schema.sql)
-##
-## $Id$
+#
+# main/oracle/queries.conf -- Oracle configuration for default schema (schema.sql)
+#
+# $Id$
- #######################################################################
- # Query config: Username
- #######################################################################
- # This is the username that will get substituted, escaped, and added
- # as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used below
- # everywhere a username substitution is needed so you you can be sure
- # the username passed from the client is escaped properly.
- #
- # Uncomment the next line, if you want the sql_user_name to mean:
- #
- # Use Stripped-User-Name, if it's there.
- # Else use User-Name, if it's there,
- # Else use hard-coded string "DEFAULT" as the user name.
- #sql_user_name = "%{Stripped-User-Name:-%{User-Name:-DEFAULT}}"
- #
- sql_user_name = "%{User-Name}"
+#######################################################################
+# Query config: Username
+#######################################################################
+# This is the username that will get substituted, escaped, and added
+# as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used below
+# everywhere a username substitution is needed so you you can be sure
+# the username passed from the client is escaped properly.
+#
+# Uncomment the next line, if you want the sql_user_name to mean:
+#
+# Use Stripped-User-Name, if it's there.
+# Else use User-Name, if it's there,
+# Else use hard-coded string "DEFAULT" as the user name.
+#sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}}"
+#
+sql_user_name = "%{User-Name}"
- #######################################################################
- # Default profile
- #######################################################################
- # This is the default profile. It is found in SQL by group membership.
- # That means that this profile must be a member of at least one group
- # which will contain the corresponding check and reply items.
- # This profile will be queried in the authorize section for every user.
- # The point is to assign all users a default profile without having to
- # manually add each one to a group that will contain the profile.
- # The SQL module will also honor the User-Profile attribute. This
- # attribute can be set anywhere in the authorize section (ie the users
- # file). It is found exactly as the default profile is found.
- # If it is set then it will *overwrite* the default profile setting.
- # The idea is to select profiles based on checks on the incoming packets,
- # not on user group membership. For example:
- # -- users file --
- # DEFAULT Service-Type == Outbound-User, User-Profile := "outbound"
- # DEFAULT Service-Type == Framed-User, User-Profile := "framed"
- #
- # By default the default_user_profile is not set
- #
- #default_user_profile = "DEFAULT"
- #
- # Determines if we will query the default_user_profile or the User-Profile
- # if the user is not found. If the profile is found then we consider the user
- # found. By default this is set to 'no'.
- #
- #query_on_not_found = no
+#######################################################################
+# Default profile
+#######################################################################
+# This is the default profile. It is found in SQL by group membership.
+# That means that this profile must be a member of at least one group
+# which will contain the corresponding check and reply items.
+# This profile will be queried in the authorize section for every user.
+# The point is to assign all users a default profile without having to
+# manually add each one to a group that will contain the profile.
+# The SQL module will also honor the User-Profile attribute. This
+# attribute can be set anywhere in the authorize section (ie the users
+# file). It is found exactly as the default profile is found.
+# If it is set then it will *overwrite* the default profile setting.
+# The idea is to select profiles based on checks on the incoming packets,
+# not on user group membership. For example:
+# -- users file --
+# DEFAULT Service-Type == Outbound-User, User-Profile := "outbound"
+# DEFAULT Service-Type == Framed-User, User-Profile := "framed"
+#
+# By default the default_user_profile is not set
+#
+#default_user_profile = "DEFAULT"
+#
+# Determines if we will query the default_user_profile or the User-Profile
+# if the user is not found. If the profile is found then we consider the user
+# found. By default this is set to 'no'.
+#
+#query_on_not_found = no
- #######################################################################
- # NAS Query
- #######################################################################
- # This query retrieves the radius clients
- #
- # 0. Row ID (currently unused)
- # 1. Name (or IP address)
- # 2. Shortname
- # 3. Type
- # 4. Secret
- # 5. Virtual server
- #######################################################################
+#######################################################################
+# NAS Query
+#######################################################################
+# This query retrieves the radius clients
+#
+# 0. Row ID (currently unused)
+# 1. Name (or IP address)
+# 2. Shortname
+# 3. Type
+# 4. Secret
+# 5. Virtual server
+#######################################################################
- client_query = "SELECT id, nasname, shortname, type, secret, server FROM ${client_table}"
- #######################################################################
- # Authorization Queries
- #######################################################################
- # These queries compare the check items for the user
- # in ${authcheck_table} and setup the reply items in
- # ${authreply_table}. You can use any query/tables
- # you want, but the return data for each row MUST
- # be in the following order:
- #
- # 0. Row ID (currently unused)
- # 1. UserName/GroupName
- # 2. Item Attr Name
- # 3. Item Attr Value
- # 4. Item Attr Operation
- #######################################################################
- #
- # WARNING: Oracle is case sensitive
- #
- # The main difference between MySQL and Oracle queries is the date format.
- # You must use the TO_DATE function to transform the radius date format to
- # the Oracle date format, and put NULL otherwise '0' in a void date field.
- #
- #######################################################################
+client_query = "\
+ SELECT id, nasname, shortname, type, secret, server \
+ FROM ${client_table}"
- authorize_check_query = "SELECT id,UserName,Attribute,Value,op FROM ${authcheck_table} WHERE Username = '%{SQL-User-Name}' ORDER BY id"
- authorize_reply_query = "SELECT id,UserName,Attribute,Value,op FROM ${authreply_table} WHERE Username = '%{SQL-User-Name}' ORDER BY id"
+#######################################################################
+# Authorization Queries
+#######################################################################
+# These queries compare the check items for the user
+# in ${authcheck_table} and setup the reply items in
+# ${authreply_table}. You can use any query/tables
+# you want, but the return data for each row MUST
+# be in the following order:
+#
+# 0. Row ID (currently unused)
+# 1. UserName/GroupName
+# 2. Item Attr Name
+# 3. Item Attr Value
+# 4. Item Attr Operation
+#######################################################################
+#
+# WARNING: Oracle is case sensitive
+#
+# The main difference between MySQL and Oracle queries is the date format.
+# You must use the TO_DATE function to transform the radius date format to
+# the Oracle date format, and put NULL otherwise '0' in a void date field.
+#
+#######################################################################
- authorize_group_check_query = "SELECT ${groupcheck_table}.id,${groupcheck_table}.GroupName,${groupcheck_table}.Attribute,${groupcheck_table}.Value,${groupcheck_table}.op FROM ${groupcheck_table},${usergroup_table} WHERE ${usergroup_table}.Username = '%{SQL-User-Name}' AND ${usergroup_table}.GroupName = ${groupcheck_table}.GroupName ORDER BY ${groupcheck_table}.id"
- authorize_group_reply_query = "SELECT ${groupreply_table}.id,${groupreply_table}.GroupName,${groupreply_table}.Attribute,${groupreply_table}.Value,${groupreply_table}.op FROM ${groupreply_table},${usergroup_table} WHERE ${usergroup_table}.Username = '%{SQL-User-Name}' AND ${usergroup_table}.GroupName = ${groupreply_table}.GroupName ORDER BY ${groupreply_table}.id"
+authorize_check_query = "\
+ SELECT id, UserName, Attribute, Value, op \
+ FROM ${authcheck_table} \
+ WHERE Username = '%{SQL-User-Name}' \
+ ORDER BY id"
- #######################################################################
- # Simultaneous Use Checking Queries
- #######################################################################
- # simul_count_query - query for the number of current connections
- # - If this is not defined, no simultaneouls use checking
- # - will be performed by this module instance
- # simul_verify_query - query to return details of current connections for verification
- # - Leave blank or commented out to disable verification step
- # - Note that the returned field order should not be changed.
- #######################################################################
+authorize_reply_query = "\
+ SELECT id, UserName, Attribute, Value, op \
+ FROM ${authreply_table} \
+ WHERE Username = '%{SQL-User-Name}' \
+ ORDER BY id"
- # Uncomment simul_count_query to enable simultaneous use checking
- # simul_count_query = "SELECT COUNT(*) FROM ${acct_table1} WHERE UserName='%{SQL-User-Name}' AND AcctStopTime IS NULL"
- simul_verify_query = "SELECT RadAcctId, AcctSessionId, UserName, NASIPAddress, NASPortId, FramedIPAddress, CallingStationId, FramedProtocol FROM ${acct_table1} WHERE UserName='%{SQL-User-Name}' AND AcctStopTime IS NULL"
+authorize_group_check_query = "\
+ SELECT \
+ ${groupcheck_table}.id, ${groupcheck_table}.GroupName, ${groupcheck_table}.Attribute, \
+ ${groupcheck_table}.Value,${groupcheck_table}.op \
+ FROM ${groupcheck_table}, ${usergroup_table} \
+ WHERE ${usergroup_table}.Username = '%{SQL-User-Name}' \
+ AND ${usergroup_table}.GroupName = ${groupcheck_table}.GroupName \
+ ORDER BY ${groupcheck_table}.id"
- #######################################################################
- # Group Membership Queries
- #######################################################################
- # group_membership_query - Check user group membership
- #######################################################################
+authorize_group_reply_query = "\
+ SELECT \
+ ${groupreply_table}.id, ${groupreply_table}.GroupName, ${groupreply_table}.Attribute, \
+ ${groupreply_table}.Value, ${groupreply_table}.op \
+ FROM ${groupreply_table}, ${usergroup_table} \
+ WHERE ${usergroup_table}.Username = '%{SQL-User-Name}' \
+ AND ${usergroup_table}.GroupName = ${groupreply_table}.GroupName \
+ ORDER BY ${groupreply_table}.id"
- group_membership_query = "SELECT GroupName FROM ${usergroup_table} WHERE UserName='%{SQL-User-Name}'"
+#######################################################################
+# Simultaneous Use Checking Queries
+#######################################################################
+# simul_count_query - query for the number of current connections
+# - If this is not defined, no simultaneouls use checking
+# - will be performed by this module instance
+# simul_verify_query - query to return details of current connections for verification
+# - Leave blank or commented out to disable verification step
+# - Note that the returned field order should not be changed.
+#######################################################################
- #######################################################################
- # Accounting and Post-Auth Queries
- #######################################################################
- # These queries insert/update accounting and authentication records.
- # The query to use is determined by the value of 'reference'.
- # This value is used as a configuration path and should resolve to one
- # or more 'query's. If reference points to multiple queries, and a query
- # fails, the next query is executed.
- #
- # Behaviour is identical to the old 1.x/2.x module, except we can now
- # fail between N queries, and query selection can be based on any
- # combination of attributes, or custom 'Acct-Status-Type' values.
- #######################################################################
- accounting {
- reference = "%{tolower:type.%{Acct-Status-Type}.query}"
+#
+# Uncomment simul_count_query to enable simultaneous use checking
+#
+#simul_count_query = "\
+# SELECT COUNT(*) \
+# FROM ${acct_table1} \
+# WHERE UserName = '%{SQL-User-Name}' \
+# AND AcctStopTime IS NULL"
- # Write SQL queries to a logfile. This is potentially useful for bulk inserts
- # when used with the rlm_sql_null driver.
+simul_verify_query = "\
+ SELECT \
+ RadAcctId, AcctSessionId, UserName, NASIPAddress, NASPortId, \
+ FramedIPAddress, CallingStationId, FramedProtocol \
+ FROM ${acct_table1} \
+ WHERE UserName='%{SQL-User-Name}' \
+ AND AcctStopTime IS NULL"
+
+#######################################################################
+# Group Membership Queries
+#######################################################################
+# group_membership_query - Check user group membership
+#######################################################################
+
+group_membership_query = "\
+ SELECT GroupName \
+ FROM ${usergroup_table} \
+ WHERE UserName='%{SQL-User-Name}'"
+
+#######################################################################
+# Accounting and Post-Auth Queries
+#######################################################################
+# These queries insert/update accounting and authentication records.
+# The query to use is determined by the value of 'reference'.
+# This value is used as a configuration path and should resolve to one
+# or more 'query's. If reference points to multiple queries, and a query
+# fails, the next query is executed.
+#
+# Behaviour is identical to the old 1.x/2.x module, except we can now
+# fail between N queries, and query selection can be based on any
+# combination of attributes, or custom 'Acct-Status-Type' values.
+#######################################################################
+accounting {
+ reference = "%{tolower:type.%{Acct-Status-Type}.query}"
+
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
# logfile = ${logdir}/accounting.sql
- type {
- accounting-on {
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- AcctStopTime = TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
- AcctSessionTime = round((TO_DATE('%S','yyyy-mm-dd hh24:mi:ss') - \
- TO_DATE(TO_CHAR(acctstarttime, 'yyyy-mm-dd hh24:mi:ss'),'yyyy-mm-dd hh24:mi:ss'))*86400), \
- AcctTerminateCause='%{Acct-Terminate-Cause}', \
- AcctStopDelay = %{Acct-Delay-Time:-0} \
- WHERE AcctStopTime IS NULL \
- AND NASIPAddress = '%{NAS-IP-Address}' \
- AND AcctStartTime <= TO_DATE('%S','yyyy-mm-dd hh24:mi:ss')"
- }
+ type {
+ accounting-on {
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctStopTime = TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
+ AcctSessionTime = round((TO_DATE('%S','yyyy-mm-dd hh24:mi:ss') - \
+ TO_DATE(TO_CHAR(acctstarttime, 'yyyy-mm-dd hh24:mi:ss'),'yyyy-mm-dd hh24:mi:ss'))*86400), \
+ AcctTerminateCause='%{%{Acct-Terminate-Cause}:-NAS-Reboot}', \
+ AcctStopDelay = %{%{Acct-Delay-Time}:-0} \
+ WHERE AcctStopTime IS NULL \
+ AND NASIPAddress = '%{NAS-IP-Address}' \
+ AND AcctStartTime <= TO_DATE('%S','yyyy-mm-dd hh24:mi:ss')"
+ }
- accounting-off {
- query = "${..accounting-on.query}"
- }
+ accounting-off {
+ query = "${..accounting-on.query}"
+ }
- start {
- query = "\
- INSERT INTO ${....acct_table1} \
- (RadAcctId, AcctSessionId, AcctUniqueId, \
- UserName, Realm, NASIPAddress, \
- NASPortId, NASPortType, AcctStartTime, \
- AcctStopTime, AcctSessionTime, AcctAuthentic, \
- ConnectInfo_start, ConnectInfo_stop, AcctInputOctets, \
- AcctOutputOctets, CalledStationId, CallingStationId, \
- AcctTerminateCause, ServiceType, FramedProtocol, \
- FramedIPAddress, AcctStartDelay, AcctStopDelay, \
- XAscendSessionSvrKey) \
- VALUES(\
- '', \
- '%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{NAS-Port-Id}', \
- '%{NAS-Port-Type}', \
- TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
- NULL, \
- '0', \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- '', \
- '0', \
- '0', \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '%{Acct-Delay-Time}', \
- '0', \
- '%{X-Ascend-Session-Svr-Key}')"
+ start {
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (RadAcctId, AcctSessionId, AcctUniqueId, \
+ UserName, Realm, NASIPAddress, \
+ NASPortId, NASPortType, AcctStartTime, \
+ AcctStopTime, AcctSessionTime, AcctAuthentic, \
+ ConnectInfo_start, ConnectInfo_stop, AcctInputOctets, \
+ AcctOutputOctets, CalledStationId, CallingStationId, \
+ AcctTerminateCause, ServiceType, FramedProtocol, \
+ FramedIPAddress, AcctStartDelay, AcctStopDelay, \
+ XAscendSessionSvrKey) \
+ VALUES(\
+ '', \
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port-Id}', \
+ '%{NAS-Port-Type}', \
+ TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
+ NULL, \
+ '0', \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ '0', \
+ '0', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Acct-Delay-Time}', \
+ '0', \
+ '%{X-Ascend-Session-Svr-Key}')"
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- AcctStartTime = TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
- AcctStartDelay = '%{Acct-Delay-Time:-0}', \
- ConnectInfo_start = '%{Connect-Info}' \
- WHERE AcctSessionId = '%{Acct-Session-Id}' \
- AND UserName = '%{SQL-User-Name}' \
- AND NASIPAddress = '%{NAS-IP-Address}' \
- AND AcctStopTime IS NULL"
- }
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctStartTime = TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
+ AcctStartDelay = '%{%{Acct-Delay-Time}:-0}', \
+ ConnectInfo_start = '%{Connect-Info}' \
+ WHERE AcctSessionId = '%{Acct-Session-Id}' \
+ AND UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{NAS-IP-Address}' \
+ AND AcctStopTime IS NULL"
+ }
- interim-update {
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- FramedIPAddress = NULLIF('%{Framed-IP-Address}', ''), \
- AcctSessionTime = '%{Acct-Session-Time}', \
- AcctInputOctets = '%{Acct-Input-Octets}' + \
- ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
- AcctOutputOctets = '%{Acct-Output-Octets}' + \
- ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296) \
- WHERE AcctSessionId = '%{Acct-Session-Id}' \
- AND UserName = '%{SQL-User-Name}' \
- AND NASIPAddress= '%{NAS-IP-Address}' \
- AND AcctStopTime IS NULL"
+ interim-update {
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', ''), \
+ AcctSessionTime = '%{Acct-Session-Time}', \
+ AcctInputOctets = '%{Acct-Input-Octets}' + \
+ ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
+ AcctOutputOctets = '%{Acct-Output-Octets}' + \
+ ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296) \
+ WHERE AcctSessionId = '%{Acct-Session-Id}' \
+ AND UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress= '%{NAS-IP-Address}' \
+ AND AcctStopTime IS NULL"
- query = "\
- INSERT into ${....acct_table1} \
- (RadAcctId, AcctSessionId, AcctUniqueId, \
- UserName, Realm, NASIPAddress, \
- NASPortId, NASPortType, AcctStartTime, \
- AcctSessionTime, AcctAuthentic, ConnectInfo_start, \
- AcctInputOctets, AcctOutputOctets, CalledStationId, \
- CallingStationId, ServiceType, FramedProtocol, \
- FramedIPAddress, AcctStartDelay, XAscendSessionSvrKey) \
- VALUES(\
- '', \
- '%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{NAS-Port-Id}', \
- '%{NAS-Port-Type}', \
- NULL, \
- '%{Acct-Session-Time}', \
- '%{Acct-Authentic}', \
- '', \
- '%{Acct-Input-Octets}' + \
- ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
- '%{Acct-Output-Octets}' + \
- ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296), \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '0', \
- '%{X-Ascend-Session-Svr-Key}')"
- }
+ query = "\
+ INSERT into ${....acct_table1} \
+ (RadAcctId, AcctSessionId, AcctUniqueId, \
+ UserName, Realm, NASIPAddress, \
+ NASPortId, NASPortType, AcctStartTime, \
+ AcctSessionTime, AcctAuthentic, ConnectInfo_start, \
+ AcctInputOctets, AcctOutputOctets, CalledStationId, \
+ CallingStationId, ServiceType, FramedProtocol, \
+ FramedIPAddress, AcctStartDelay, XAscendSessionSvrKey) \
+ VALUES(\
+ '', \
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port-Id}', \
+ '%{NAS-Port-Type}', \
+ NULL, \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', \
+ '', \
+ '%{Acct-Input-Octets}' + \
+ ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
+ '%{Acct-Output-Octets}' + \
+ ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296), \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '0', \
+ '%{X-Ascend-Session-Svr-Key}')"
+ }
- stop {
- query = "\
- UPDATE ${....acct_table2} \
- SET \
- AcctStopTime = TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
- AcctSessionTime = '%{Acct-Session-Time}', \
- AcctInputOctets = '%{Acct-Input-Octets}' + \
- ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
- AcctOutputOctets = '%{Acct-Output-Octets}' + \
- ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296), \
- AcctTerminateCause = '%{Acct-Terminate-Cause}', \
- AcctStopDelay = '%{Acct-Delay-Time:-0}', \
- ConnectInfo_stop = '%{Connect-Info}' \
- WHERE AcctSessionId = '%{Acct-Session-Id}' \
- AND UserName = '%{SQL-User-Name}' \
- AND NASIPAddress = '%{NAS-IP-Address}' \
- AND AcctStopTime IS NULL"
+ stop {
+ query = "\
+ UPDATE ${....acct_table2} \
+ SET \
+ AcctStopTime = TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
+ AcctSessionTime = '%{Acct-Session-Time}', \
+ AcctInputOctets = '%{Acct-Input-Octets}' + \
+ ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
+ AcctOutputOctets = '%{Acct-Output-Octets}' + \
+ ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296), \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ AcctStopDelay = '%{%{Acct-Delay-Time}:-0}', \
+ ConnectInfo_stop = '%{Connect-Info}' \
+ WHERE AcctSessionId = '%{Acct-Session-Id}' \
+ AND UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{NAS-IP-Address}' \
+ AND AcctStopTime IS NULL"
- query = "\
- "INSERT into ${....acct_table2} \
- (RadAcctId, AcctSessionId, AcctUniqueId, \
- UserName, Realm, NASIPAddress, \
- NASPortId, NASPortType, AcctStartTime, \
- AcctStopTime, AcctSessionTime, AcctAuthentic, \
- ConnectInfo_start, ConnectInfo_stop, AcctInputOctets, \
- AcctOutputOctets, CalledStationId, CallingStationId, \
- AcctTerminateCause, ServiceType, FramedProtocol, \
- FramedIPAddress, AcctStartDelay, AcctStopDelay) \
- VALUES(\
- '', \
- '%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{NAS-Port-Id}', \
- '%{NAS-Port-Type}', \
- NULL, \
- TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
- '%{Acct-Session-Time}', \
- '%{Acct-Authentic}', \
- '', \
- '%{Connect-Info}', \
- '%{Acct-Input-Octets}' + \
- ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
- '%{Acct-Output-Octets}' + \
- ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296), \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Acct-Terminate-Cause}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '0', \
- '%{Acct-Delay-Time:-0}')"
+ query = "\
+ INSERT into ${....acct_table2} \
+ (RadAcctId, AcctSessionId, AcctUniqueId, \
+ UserName, Realm, NASIPAddress, \
+ NASPortId, NASPortType, AcctStartTime, \
+ AcctStopTime, AcctSessionTime, AcctAuthentic, \
+ ConnectInfo_start, ConnectInfo_stop, AcctInputOctets, \
+ AcctOutputOctets, CalledStationId, CallingStationId, \
+ AcctTerminateCause, ServiceType, FramedProtocol, \
+ FramedIPAddress, AcctStartDelay, AcctStopDelay) \
+ VALUES(\
+ '', \
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port-Id}', \
+ '%{NAS-Port-Type}', \
+ NULL, \
+ TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', \
+ '', \
+ '%{Connect-Info}', \
+ '%{Acct-Input-Octets}' + \
+ ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
+ '%{Acct-Output-Octets}' + \
+ ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296), \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Acct-Terminate-Cause}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '0', \
+ '%{%{Acct-Delay-Time}:-0}')"
- }
}
}
+}
- #######################################################################
- # Authentication Logging Queries
- #######################################################################
- # postauth_query - Insert some info after authentication
- #######################################################################
+#######################################################################
+# Authentication Logging Queries
+#######################################################################
+# postauth_query - Insert some info after authentication
+#######################################################################
- post-auth {
- # Write SQL queries to a logfile. This is potentially useful for bulk inserts
- # when used with the rlm_sql_null driver.
-# logfile = ${logdir}/post-auth.sql
- query = "\
- INSERT INTO ${..postauth_table} \
- (username, pass, reply, authdate) \
- VALUES (\
+post-auth {
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
+# logfile = ${logdir}/post-auth.sql
+ query = "\
+ INSERT INTO ${..postauth_table} \
+ (username, pass, reply, authdate) \
+ VALUES (\
'%{User-Name}', \
'%{%{User-Password}:-%{Chap-Password}}', \
'%{reply:Packet-Type}', \
TO_TIMESTAMP('%S','YYYY-MM-DDHH24:MI:SS'))"
- }
+}
CREATE SEQUENCE realms_seq START WITH 1 INCREMENT BY 1;
CREATE TABLE radhuntgroup (
- id INT PRIMARY KEY,
- GroupName VARCHAR(64) NOT NULL,
- Nasipaddress VARCHAR(15) UNIQUE NOT NULL,
- NASPortID VARCHAR(15)
+ id INT PRIMARY KEY,
+ GroupName VARCHAR(64) NOT NULL,
+ Nasipaddress VARCHAR(15) UNIQUE NOT NULL,
+ NASPortID VARCHAR(15)
);
CREATE SEQUENCE radhuntgroup_seq START WITH 1 INCREMENT BY 1;
CREATE OR REPLACE TRIGGER radhuntgroup_serialnumber
- BEFORE INSERT OR UPDATE OF id ON radhuntgroup
- FOR EACH ROW
- BEGIN
- if ( :new.id = 0 or :new.id is null ) then
- SELECT radhuntgroup_seq.nextval into :new.id from dual;
- end if;
- END;
+ BEFORE INSERT OR UPDATE OF id ON radhuntgroup
+ FOR EACH ROW
+ BEGIN
+ if ( :new.id = 0 or :new.id is null ) then
+ SELECT radhuntgroup_seq.nextval into :new.id from dual;
+ end if;
+ END;
CREATE TABLE radpostauth (
- id INT PRIMARY KEY,
- UserName VARCHAR(64) NOT NULL,
- Pass VARCHAR(64),
- Reply VARCHAR(64),
- AuthDate DATE
+ id INT PRIMARY KEY,
+ UserName VARCHAR(64) NOT NULL,
+ Pass VARCHAR(64),
+ Reply VARCHAR(64),
+ AuthDate DATE
);
CREATE SEQUENCE radpostauth_seq START WITH 1 INCREMENT BY 1;
CREATE OR REPLACE TRIGGER radpostauth_TRIG
- BEFORE INSERT OR UPDATE OF id ON radpostauth
- FOR EACH ROW
- BEGIN
- if ( :new.id = 0 or :new.id is null ) then
- SELECT radpostauth_seq.nextval into :new.id from dual;
- end if;
- if (:new.AuthDate is null) then
- select sysdate into :new.AuthDate from dual;
- end if;
- END;
+ BEFORE INSERT OR UPDATE OF id ON radpostauth
+ FOR EACH ROW
+ BEGIN
+ if ( :new.id = 0 or :new.id is null ) then
+ SELECT radpostauth_seq.nextval into :new.id from dual;
+ end if;
+ if (:new.AuthDate is null) then
+ select sysdate into :new.AuthDate from dual;
+ end if;
+ END;
/
* Table structure for table 'nas'
*/
CREATE TABLE nas (
- id INT PRIMARY KEY,
- nasname VARCHAR(128),
- shortname VARCHAR(32),
- type VARCHAR(30),
- ports INT,
- secret VARCHAR(60),
- server VARCHAR(64),
- community VARCHAR(50),
- description VARCHAR(200)
+ id INT PRIMARY KEY,
+ nasname VARCHAR(128),
+ shortname VARCHAR(32),
+ type VARCHAR(30),
+ ports INT,
+ secret VARCHAR(60),
+ server VARCHAR(64),
+ community VARCHAR(50),
+ description VARCHAR(200)
);
CREATE SEQUENCE nas_seq START WITH 1 INCREMENT BY 1;
CREATE OR REPLACE FUNCTION strip_dot (VARCHAR) RETURNS TIMESTAMPTZ AS '
DECLARE
- original_timestamp ALIAS FOR $1;
+ original_timestamp ALIAS FOR $1;
BEGIN
IF original_timestamp = '''' THEN
RETURN NULL;
- END IF;
- IF substring(original_timestamp from 1 for 1) = ''.'' THEN
- RETURN substring(original_timestamp from 2);
- ELSE
- RETURN original_timestamp;
- END IF;
+ END IF;
+ IF substring(original_timestamp from 1 for 1) = ''.'' THEN
+ RETURN substring(original_timestamp from 2);
+ ELSE
+ RETURN original_timestamp;
+ END IF;
END;
' LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION pick_id (VARCHAR, VARCHAR) RETURNS VARCHAR AS '
DECLARE
- h323confid ALIAS FOR $1;
- callid ALIAS FOR $2;
+ h323confid ALIAS FOR $1;
+ callid ALIAS FOR $2;
BEGIN
- IF h323confid <> '''' THEN
- RETURN h323confid;
- END IF;
- IF callid <> '''' THEN
- RETURN callid;
- END IF;
+ IF h323confid <> '''' THEN
+ RETURN h323confid;
+ END IF;
+ IF callid <> '''' THEN
+ RETURN callid;
+ END IF;
RETURN NULL;
END;
' LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION upd_radgroups() RETURNS trigger AS'
DECLARE
- v_groupname varchar;
+ v_groupname varchar;
BEGIN
- SELECT INTO v_groupname GroupName FROM radusergroup WHERE CalledStationId = NEW.CalledStationId AND UserName = NEW.UserName;
- IF FOUND THEN
- UPDATE radacct SET GroupName = v_groupname WHERE RadAcctId = NEW.RadAcctId;
- END IF;
+ SELECT INTO v_groupname GroupName FROM radusergroup WHERE CalledStationId = NEW.CalledStationId AND UserName = NEW.UserName;
+ IF FOUND THEN
+ UPDATE radacct SET GroupName = v_groupname WHERE RadAcctId = NEW.RadAcctId;
+ END IF;
- RETURN NEW;
+ RETURN NEW;
END
'LANGUAGE plpgsql;
# Else use User-Name, if it's there,
# Else use hard-coded string "none" as the user name.
#
- #sql_user_name = "%{Stripped-User-Name:-%{User-Name:-none}}"
+ #sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-none}}"
#
sql_user_name = "%{User-Name}"
start {
query = "INSERT INTO ${....acct_table1}%{h323-call-type} \
(RadiusServerName, UserName, NASIPAddress, AcctTime, CalledStationId, \
- CallingStationId, AcctDelayTime, h323gwid, h323callorigin, \
- h323setuptime, H323ConnectTime, callid) \
+ CallingStationId, AcctDelayTime, h323gwid, h323callorigin, \
+ h323setuptime, H323ConnectTime, callid) \
VALUES(\
'${radius_server_name}', '%{SQL-User-Name}', \
'%{NAS-IP-Address}', now(), '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', '%{Acct-Delay-Time:-0}', '%{h323-gw-id}', \
+ '%{Calling-Station-Id}', '%{%{Acct-Delay-Time}:-0}', '%{h323-gw-id}', \
'%{h323-call-origin}', strip_dot('%{h323-setup-time}'), \
strip_dot('%{h323-connect-time}'), pick_id('%{h323-conf-id}', \
'%{call-id}'))"
stop {
query = "INSERT INTO $....acct_table2}%{h323-call-type} \
(RadiusServerName, UserName, NASIPAddress, AcctTime, \
- AcctSessionTime, AcctInputOctets, AcctOutputOctets, CalledStationId, \
- CallingStationId, AcctDelayTime, H323RemoteAddress, H323VoiceQuality, \
- CiscoNASPort, h323callorigin, callid, h323connecttime, \
- h323disconnectcause, h323disconnecttime, h323gwid, h323setuptime) \
+ AcctSessionTime, AcctInputOctets, AcctOutputOctets, CalledStationId, \
+ CallingStationId, AcctDelayTime, H323RemoteAddress, H323VoiceQuality, \
+ CiscoNASPort, h323callorigin, callid, h323connecttime, \
+ h323disconnectcause, h323disconnecttime, h323gwid, h323setuptime) \
VALUES(\
'${radius_server_name}', '%{SQL-User-Name}', '%{NAS-IP-Address}', \
- NOW(), '%{Acct-Session-Time:-0}', \
- '%{Acct-Input-Octets:-0}', '%{Acct-Output-Octets:-0}', \
+ NOW(), '%{%{Acct-Session-Time}:-0}', \
+ '%{%{Acct-Input-Octets}:-0}', '%{%{Acct-Output-Octets}:-0}', \
'%{Called-Station-Id}', '%{Calling-Station-Id}', \
- '%{Acct-Delay-Time:-0}', NULLIF('%{h323-remote-address}', '')::inet, \
+ '%{%{Acct-Delay-Time}:-0}', NULLIF('%{h323-remote-address}', '')::inet, \
NULLIF('%{h323-voice-quality}','')::integer, \
NULLIF('%{Cisco-NAS-Port}', ''), \
'%{h323-call-origin}', pick_id('%{h323-conf-id}', '%{call-id}'), \
strip_dot('%{h323-connect-time}'), '%{h323-disconnect-cause}', \
strip_dot('%{h323-disconnect-time}'), '%{h323-gw-id}', \
strip_dot('%{h323-setup-time}'))"
- }
- }
- }
+ }
+ }
+ }
- # -*- text -*-
- ##
- ## dialup.conf -- PostgreSQL configuration for default schema (schema.sql)
- ##
- ## $Id$
-
- # Safe characters list for sql queries. Everything else is replaced
- # with their mime-encoded equivalents.
- # The default list should be ok
- # safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"
-
- #######################################################################
- # Query config: Username
- #######################################################################
- # This is the username that will get substituted, escaped, and added
- # as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used
- # below everywhere a username substitution is needed so you you can
- # be sure the username passed from the client is escaped properly.
- #
- # Uncomment the next line, if you want the sql_user_name to mean:
- #
- # Use Stripped-User-Name, if it's there.
- # Else use User-Name, if it's there,
- # Else use hard-coded string "none" as the user name.
- #
- #sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-none}}"
-
- sql_user_name = "%{User-Name}"
-
- #######################################################################
- # Default profile
- #######################################################################
- # This is the default profile. It is found in SQL by group membership.
- # That means that this profile must be a member of at least one group
- # which will contain the corresponding check and reply items.
- # This profile will be queried in the authorize section for every user.
- # The point is to assign all users a default profile without having to
- # manually add each one to a group that will contain the profile.
- # The SQL module will also honor the User-Profile attribute. This
- # attribute can be set anywhere in the authorize section (ie the users
- # file). It is found exactly as the default profile is found.
- # If it is set then it will *overwrite* the default profile setting.
- # The idea is to select profiles based on checks on the incoming
- # packets, not on user group membership. For example:
- # -- users file --
- # DEFAULT Service-Type == Outbound-User, User-Profile := "outbound"
- # DEFAULT Service-Type == Framed-User, User-Profile := "framed"
- #
- # By default the default_user_profile is not set
- #
- # default_user_profile = "DEFAULT"
-
- #######################################################################
- # NAS Query
- #######################################################################
- # This query retrieves the radius clients
- #
- # 0. Row ID (currently unused)
- # 1. Name (or IP address)
- # 2. Shortname
- # 3. Type
- # 4. Secret
- # 5. Server
- #######################################################################
-
- client_query = "SELECT id, nasname, shortname, type, secret, server FROM ${client_table}"
-
- #######################################################################
- # Authorization Queries
- #######################################################################
- # These queries compare the check items for the user
- # in ${authcheck_table} and setup the reply items in
- # ${authreply_table}. You can use any query/tables
- # you want, but the return data for each row MUST
- # be in the following order:
- #
- # 0. Row ID (currently unused)
- # 1. UserName/GroupName
- # 2. Item Attr Name
- # 3. Item Attr Value
- # 4. Item Attr Operation
- #######################################################################
-
- # Use these for case insensitive usernames. WARNING: Slower queries!
- # authorize_check_query = "SELECT id, UserName, Attribute, Value, Op \
- # FROM ${authcheck_table} \
- # WHERE LOWER(UserName) = LOWER('%{SQL-User-Name}') \
- # ORDER BY id"
- # authorize_reply_query = "SELECT id, UserName, Attribute, Value, Op \
- # FROM ${authreply_table} \
- # WHERE LOWER(UserName) = LOWER('%{SQL-User-Name}') \
- # ORDER BY id"
-
- authorize_check_query = "SELECT id, UserName, Attribute, Value, Op \
- FROM ${authcheck_table} \
- WHERE Username = '%{SQL-User-Name}' \
- ORDER BY id"
-
- authorize_reply_query = "SELECT id, UserName, Attribute, Value, Op \
- FROM ${authreply_table} \
- WHERE Username = '%{SQL-User-Name}' \
- ORDER BY id"
-
- # Use these for case insensitive usernames. WARNING: Slower queries!
- # authorize_group_check_query = "SELECT ${groupcheck_table}.id, ${groupcheck_table}.GroupName, \
- # ${groupcheck_table}.Attribute, ${groupcheck_table}.Value, ${groupcheck_table}.Op \
- # FROM ${groupcheck_table}, ${usergroup_table} \
- # WHERE LOWER(${usergroup_table}.UserName) = LOWER('%{SQL-User-Name}') AND ${usergroup_table}.GroupName = ${groupcheck_table}.GroupName \
- # ORDER BY ${groupcheck_table}.id"
- # authorize_group_reply_query = "SELECT ${groupreply_table}.id, ${groupreply_table}.GroupName, \
- # ${groupreply_table}.Attribute, ${groupreply_table}.Value, ${groupreply_table}.Op \
- # FROM ${groupreply_table}, ${usergroup_table} \
- # WHERE LOWER(${usergroup_table}.UserName) = LOWER('%{SQL-User-Name}') AND ${usergroup_table}.GroupName = ${groupreply_table}.GroupName \
- # ORDER BY ${groupreply_table}.id"
-
- authorize_group_check_query = "SELECT id, GroupName, Attribute, Value, op \
- FROM ${groupcheck_table} \
- WHERE GroupName = '%{Sql-Group}' \
- ORDER BY id"
-
- authorize_group_reply_query = "SELECT id, GroupName, Attribute, Value, op \
- FROM ${groupreply_table} \
- WHERE GroupName = '%{Sql-Group}' \
- ORDER BY id"
-
- #######################################################################
- # Simultaneous Use Checking Queries
- #######################################################################
- # simul_count_query - query for the number of current connections
- # - If this is not defined, no simultaneous use checking
- # - will be performed by this module instance
- # simul_verify_query - query to return details of current connections for verification
- # - Leave blank or commented out to disable verification step
- # - Note that the returned field order should not be changed.
- #######################################################################
-
- # Uncomment simul_count_query to enable simultaneous use checking
- # simul_count_query = "SELECT COUNT(*) FROM ${acct_table1} WHERE UserName='%{SQL-User-Name}' AND AcctStopTime IS NULL"
- # simul_verify_query = "SELECT RadAcctId, AcctSessionId, UserName, NASIPAddress, NASPortId, FramedIPAddress, CallingStationId, FramedProtocol FROM ${acct_table1} WHERE UserName='%{SQL-User-Name}' AND AcctStopTime IS NULL"
-
- #######################################################################
- # Group Membership Queries
- #######################################################################
- # group_membership_query - Check user group membership
- #######################################################################
-
- # Use these for case insensitive usernames. WARNING: Slower queries!
- # group_membership_query = "SELECT GroupName FROM ${usergroup_table} WHERE LOWER(UserName) = LOWER('%{SQL-User-Name}') ORDER BY priority"
-
- group_membership_query = "SELECT GroupName FROM ${usergroup_table} WHERE UserName='%{SQL-User-Name}' ORDER BY priority"
-
- #######################################################################
- # Accounting and Post-Auth Queries
- #######################################################################
- # These queries insert/update accounting and authentication records.
- # The query to use is determined by the value of 'reference'.
- # This value is used as a configuration path and should resolve to one
- # or more 'query's. If reference points to multiple queries, and a query
- # fails, the next query is executed.
- #
- # Behaviour is identical to the old 1.x/2.x module, except we can now
- # fail between N queries, and query selection can be based on any
- # combination of attributes, or custom 'Acct-Status-Type' values.
- #######################################################################
- accounting {
- reference = "%{tolower:type.%{Acct-Status-Type}.query}"
-
- # Write SQL queries to a logfile. This is potentially useful for bulk inserts
- # when used with the rlm_sql_null driver.
-# logfile = ${logdir}/accounting.sql
-
- type {
- accounting-on {
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- AcctStopTime = ('%S'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval), \
- AcctSessionTime = (EXTRACT(EPOCH FROM ('%S'::timestamp with time zone - AcctStartTime::timestamp with time zone \
- - '%{%{Acct-Delay-Time}:-0}'::interval)))::BIGINT, \
- AcctTerminateCause = '%{Acct-Terminate-Cause}', \
- AcctStopDelay = 0 \
- WHERE AcctStopTime IS NULL \
- AND NASIPAddress= '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
- AND AcctStartTime <= '%S'::timestamp"
- }
-
- accounting-off {
- query = "${..accounting-on.query}"
- }
-
- start {
- query = "\
- INSERT INTO ${....acct_table1} \
- (AcctSessionId, AcctUniqueId, UserName, \
- Realm, NASIPAddress, NASPortId, \
- NASPortType, AcctStartTime, AcctAuthentic, \
- ConnectInfo_start, CalledStationId, CallingStationId, \
- ServiceType, FramedProtocol, FramedIPAddress, \
- AcctStartDelay, XAscendSessionSvrKey) \
- VALUES(\
- '%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- NULLIF('%{Realm}', ''), \
- '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}', \
- %{%{NAS-Port}:-NULL}, \
- '%{NAS-Port-Type}', \
- ('%S'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval), \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- NULLIF('%{Framed-IP-Address}', '')::inet, \
- 0, \
- '%{X-Ascend-Session-Svr-Key}')"
-
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- AcctStartTime = ('%S'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval), \
- AcctStartDelay = 0, \
- ConnectInfo_start = '%{Connect-Info}' \
- WHERE AcctSessionId = '%{Acct-Session-Id}' \
- AND UserName = '%{SQL-User-Name}' \
- AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
- AND AcctStopTime IS NULL"
- }
-
- interim-update {
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
- AcctSessionTime = '%{Acct-Session-Time}', \
- AcctInputOctets = (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + \
- '%{%{Acct-Input-Octets}:-0}'::bigint), \
- AcctOutputOctets = (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + \
- '%{%{Acct-Output-Octets}:-0}'::bigint) \
- WHERE AcctSessionId = '%{Acct-Session-Id}' \
- AND UserName = '%{SQL-User-Name}' \
- AND NASIPAddress= '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
- AND AcctStopTime IS NULL"
-
- query = "\
- INSERT INTO ${....acct_table1} \
- (AcctSessionId, AcctUniqueId, UserName, \
- Realm, NASIPAddress, NASPortId, \
- NASPortType, AcctStartTime, AcctSessionTime, \
- AcctAuthentic, AcctInputOctets, AcctOutputOctets, \
- CalledStationId, CallingStationId, ServiceType, \
- FramedProtocol, FramedIPAddress, XAscendSessionSvrKey) \
- VALUES(\
- '%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- NULLIF('%{Realm}', ''), \
- '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}', \
- %{%{NAS-Port}:-NULL}, \
- '%{NAS-Port-Type}', \
- ('%S'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval - \
- '%{%{Acct-Session-Time}:-0}'::interval), \
- '%{Acct-Session-Time}', \
- '%{Acct-Authentic}', \
- (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + \
- '%{%{Acct-Input-Octets}:-0}'::bigint), \
- (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + \
- '%{%{Acct-Output-Octets}:-0}'::bigint), \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- NULLIF('%{Framed-IP-Address}', '')::inet, \
- '%{X-Ascend-Session-Svr-Key}')"
- }
-
- stop {
- query = "\
- UPDATE ${....acct_table2} \
- SET \
- AcctStopTime = ('%S'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval), \
- AcctSessionTime = CASE WHEN '%{Acct-Session-Time}' = ''\
- THEN \
- (EXTRACT(EPOCH FROM ('%S'::TIMESTAMP WITH TIME ZONE - \
- AcctStartTime::TIMESTAMP WITH TIME ZONE - \
- '%{%{Acct-Delay-Time}:-0}'::INTERVAL)))::BIGINT \
- ELSE \
- NULLIF('%{Acct-Session-Time}','')::BIGINT END, \
- AcctInputOctets = (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + \
- '%{%{Acct-Input-Octets}:-0}'::bigint), \
- AcctOutputOctets = (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + \
+# -*- text -*-
+#
+# main/postgresql/queries.conf -- PostgreSQL configuration for default schema (schema.sql)
+#
+# $Id$
+
+# Safe characters list for sql queries. Everything else is replaced
+# with their mime-encoded equivalents.
+# The default list should be ok
+# safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"
+
+#######################################################################
+# Query config: Username
+#######################################################################
+# This is the username that will get substituted, escaped, and added
+# as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used
+# below everywhere a username substitution is needed so you you can
+# be sure the username passed from the client is escaped properly.
+#
+# Uncomment the next line, if you want the sql_user_name to mean:
+#
+# Use Stripped-User-Name, if it's there.
+# Else use User-Name, if it's there,
+# Else use hard-coded string "none" as the user name.
+#
+#sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-none}}"
+
+sql_user_name = "%{User-Name}"
+
+#######################################################################
+# Default profile
+#######################################################################
+# This is the default profile. It is found in SQL by group membership.
+# That means that this profile must be a member of at least one group
+# which will contain the corresponding check and reply items.
+# This profile will be queried in the authorize section for every user.
+# The point is to assign all users a default profile without having to
+# manually add each one to a group that will contain the profile.
+# The SQL module will also honor the User-Profile attribute. This
+# attribute can be set anywhere in the authorize section (ie the users
+# file). It is found exactly as the default profile is found.
+# If it is set then it will *overwrite* the default profile setting.
+# The idea is to select profiles based on checks on the incoming
+# packets, not on user group membership. For example:
+# -- users file --
+# DEFAULT Service-Type == Outbound-User, User-Profile := "outbound"
+# DEFAULT Service-Type == Framed-User, User-Profile := "framed"
+#
+# By default the default_user_profile is not set
+#
+# default_user_profile = "DEFAULT"
+
+#######################################################################
+# Open Query
+#######################################################################
+# This query is run whenever a new connection is opened.
+# It is commented out by default.
+#
+# If you have issues with connections hanging for too long, uncomment
+# the next line, and set the timeout in milliseconds. As a general
+# rule, if the queries take longer than a second, something is wrong
+# with the database.
+#open_query = "set statement_timeout to 1000"
+
+#######################################################################
+# NAS Query
+#######################################################################
+# This query retrieves the radius clients
+#
+# 0. Row ID (currently unused)
+# 1. Name (or IP address)
+# 2. Shortname
+# 3. Type
+# 4. Secret
+# 5. Server
+#######################################################################
+
+client_query = "\
+ SELECT id, nasname, shortname, type, secret, server \
+ FROM ${client_table}"
+
+#######################################################################
+# Authorization Queries
+#######################################################################
+# These queries compare the check items for the user
+# in ${authcheck_table} and setup the reply items in
+# ${authreply_table}. You can use any query/tables
+# you want, but the return data for each row MUST
+# be in the following order:
+#
+# 0. Row ID (currently unused)
+# 1. UserName/GroupName
+# 2. Item Attr Name
+# 3. Item Attr Value
+# 4. Item Attr Operation
+#######################################################################
+
+#
+# Use these for case insensitive usernames. WARNING: Slower queries!
+#
+#authorize_check_query = "\
+# SELECT id, UserName, Attribute, Value, Op \
+# FROM ${authcheck_table} \
+# WHERE LOWER(UserName) = LOWER('%{SQL-User-Name}') \
+# ORDER BY id"
+
+#authorize_reply_query = "\
+# SELECT id, UserName, Attribute, Value, Op \
+# FROM ${authreply_table} \
+# WHERE LOWER(UserName) = LOWER('%{SQL-User-Name}') \
+# ORDER BY id"
+
+authorize_check_query = "\
+ SELECT id, UserName, Attribute, Value, Op \
+ FROM ${authcheck_table} \
+ WHERE Username = '%{SQL-User-Name}' \
+ ORDER BY id"
+
+authorize_reply_query = "\
+ SELECT id, UserName, Attribute, Value, Op \
+ FROM ${authreply_table} \
+ WHERE Username = '%{SQL-User-Name}' \
+ ORDER BY id"
+
+#
+# Use these for case insensitive usernames. WARNING: Slower queries!
+#
+#authorize_group_check_query = "\
+# SELECT \
+# ${groupcheck_table}.id, ${groupcheck_table}.GroupName, ${groupcheck_table}.Attribute, \
+# ${groupcheck_table}.Value, ${groupcheck_table}.Op \
+# FROM ${groupcheck_table}, ${usergroup_table} \
+# WHERE LOWER(${usergroup_table}.UserName) = LOWER('%{SQL-User-Name}') \
+# AND ${usergroup_table}.GroupName = ${groupcheck_table}.GroupName \
+# ORDER BY ${groupcheck_table}.id"
+
+#authorize_group_reply_query = "\
+# SELECT \
+# ${groupreply_table}.id, ${groupreply_table}.GroupName, \
+# ${groupreply_table}.Attribute, ${groupreply_table}.Value, ${groupreply_table}.Op \
+# FROM ${groupreply_table}, ${usergroup_table} \
+# WHERE LOWER(${usergroup_table}.UserName) = LOWER('%{SQL-User-Name}') \
+# AND ${usergroup_table}.GroupName = ${groupreply_table}.GroupName \
+# ORDER BY ${groupreply_table}.id"
+
+authorize_group_check_query = "\
+ SELECT id, GroupName, Attribute, Value, op \
+ FROM ${groupcheck_table} \
+ WHERE GroupName = '%{Sql-Group}' \
+ ORDER BY id"
+
+authorize_group_reply_query = "\
+ SELECT id, GroupName, Attribute, Value, op \
+ FROM ${groupreply_table} \
+ WHERE GroupName = '%{Sql-Group}' \
+ ORDER BY id"
+
+#######################################################################
+# Simultaneous Use Checking Queries
+#######################################################################
+# simul_count_query - query for the number of current connections
+# - If this is not defined, no simultaneous use checking
+# - will be performed by this module instance
+# simul_verify_query - query to return details of current connections for verification
+# - Leave blank or commented out to disable verification step
+# - Note that the returned field order should not be changed.
+#######################################################################
+
+#
+# Uncomment simul_count_query to enable simultaneous use checking
+#
+#simul_count_query = "\
+# SELECT COUNT(*) \
+# FROM ${acct_table1} \
+# WHERE UserName='%{SQL-User-Name}' \
+# AND AcctStopTime IS NULL"
+
+#simul_verify_query = "\
+# SELECT RadAcctId, AcctSessionId, UserName, NASIPAddress, NASPortId, FramedIPAddress, CallingStationId, \
+# FramedProtocol \
+# FROM ${acct_table1} \
+# WHERE UserName='%{SQL-User-Name}' \
+# AND AcctStopTime IS NULL"
+
+#######################################################################
+# Group Membership Queries
+#######################################################################
+# group_membership_query - Check user group membership
+#######################################################################
+
+# Use these for case insensitive usernames. WARNING: Slower queries!
+#group_membership_query = "\
+# SELECT GroupName \
+# FROM ${usergroup_table} \
+# WHERE LOWER(UserName) = LOWER('%{SQL-User-Name}') \
+# ORDER BY priority"
+
+group_membership_query = "\
+ SELECT GroupName \
+ FROM ${usergroup_table} \
+ WHERE UserName='%{SQL-User-Name}' \
+ ORDER BY priority"
+
+#######################################################################
+# Accounting and Post-Auth Queries
+#######################################################################
+# These queries insert/update accounting and authentication records.
+# The query to use is determined by the value of 'reference'.
+# This value is used as a configuration path and should resolve to one
+# or more 'query's. If reference points to multiple queries, and a query
+# fails, the next query is executed.
+#
+# Behaviour is identical to the old 1.x/2.x module, except we can now
+# fail between N queries, and query selection can be based on any
+# combination of attributes, or custom 'Acct-Status-Type' values.
+#######################################################################
+
+accounting {
+ reference = "%{tolower:type.%{%{Acct-Status-Type}:-none}.query}"
+
+ session_identifier="(AcctUniqueId = '%{Acct-Unique-Session-Id}')"
+
+# Old method of identifying a session, should only be used for backwards
+# compatibility (and even then it's probably ok to use AcctUniqueId).
+# session_identifier="\
+# (AcctSessionId = '%{Acct-Session-Id}' \
+# AND UserName = '%{SQL-User-Name}' \
+# AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}')"
+
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
+# logfile = ${logdir}/accounting.sql
+
+ column_list = "\
+ AcctSessionId, AcctUniqueId, UserName, \
+ Realm, NASIPAddress, NASPortId, \
+ NASPortType, AcctStartTime, AcctUpdateTime, \
+ AcctStopTime, AcctSessionTime, AcctAuthentic, \
+ ConnectInfo_start, ConnectInfo_Stop, AcctInputOctets, \
+ AcctOutputOctets, CalledStationId, CallingStationId, \
+ AcctTerminateCause, ServiceType, FramedProtocol, \
+ FramedIpAddress"
+
+ type {
+ accounting-on {
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctStopTime = TO_TIMESTAMP(%{integer:Event-Timestamp}), \
+ AcctUpdateTime = TO_TIMESTAMP(%{integer:Event-Timestamp}), \
+ AcctSessionTime = (%{integer:Event-Timestamp} - EXTRACT(EPOCH FROM(AcctStartTime))), \
+ AcctTerminateCause = '%{%{Acct-Terminate-Cause}:-NAS-Reboot}', \
+ WHERE AcctStopTime IS NULL \
+ AND NASIPAddress= '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
+ AND AcctStartTime <= '%S'::timestamp"
+ }
+
+ accounting-off {
+ query = "${..accounting-on.query}"
+ }
+
+ start {
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (${...column_list}) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ NULLIF('%{Realm}', ''), \
+ '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}', \
+ %{%{NAS-Port}:-NULL}, \
+ '%{NAS-Port-Type}', \
+ TO_TIMESTAMP(%{integer:Event-Timestamp}), \
+ TO_TIMESTAMP(%{integer:Event-Timestamp}), \
+ NULL, \
+ 0, \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ NULL, \
+ 0, \
+ 0, \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ NULL, \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ NULLIF('%{Framed-IP-Address}', '')::inet)"
+
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctStartTime = TO_TIMESTAMP(%{integer:Event-Timestamp}), \
+ AcctUpdateTime = TO_TIMESTAMP(%{integer:Event-Timestamp}), \
+ ConnectInfo_start = '%{Connect-Info}' \
+ WHERE ${...session_identifier} \
+ AND AcctStopTime IS NULL"
+
+ # and again where we don't have "AND AcctStopTime IS NULL"
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctStartTime = TO_TIMESTAMP(%{integer:Event-Timestamp}), \
+ AcctUpdateTime = TO_TIMESTAMP(%{integer:Event-Timestamp}), \
+ ConnectInfo_start = '%{Connect-Info}' \
+ WHERE ${...session_identifier}"
+ }
+
+ interim-update {
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
+ AcctSessionTime = %{%{Acct-Session-Time}:-NULL}, \
+ AcctInterval = (%{integer:Event-Timestamp} - EXTRACT(EPOCH FROM (COALESCE(AcctUpdateTime, AcctStartTime)))), \
+ AcctUpdateTime = TO_TIMESTAMP(%{integer:Event-Timestamp}), \
+ AcctInputOctets = (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Input-Octets}:-0}'::bigint), \
+ AcctOutputOctets = (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Output-Octets}:-0}'::bigint) \
+ WHERE ${...session_identifier} \
+ AND AcctStopTime IS NULL"
+
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (${...column_list}) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ NULLIF('%{Realm}', ''), \
+ '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}', \
+ %{%{NAS-Port}:-NULL}, \
+ '%{NAS-Port-Type}', \
+ TO_TIMESTAMP(%{integer:Event-Timestamp}), \
+ TO_TIMESTAMP(%{integer:Event-Timestamp}), \
+ NULL, \
+ %{%{Acct-Session-Time}:-NULL}, \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ NULL, \
+ (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Input-Octets}:-0}'::bigint), \
+ (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + \
'%{%{Acct-Output-Octets}:-0}'::bigint), \
- AcctTerminateCause = '%{Acct-Terminate-Cause}', \
- AcctStopDelay = 0, \
- FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
- ConnectInfo_stop = '%{Connect-Info}' \
- WHERE AcctSessionId = '%{Acct-Session-Id}' \
- AND UserName = '%{SQL-User-Name}' \
- AND NASIPAddress = '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}' \
- AND AcctStopTime IS NULL"
-
- query = "\
- INSERT INTO ${....acct_table2} \
- (AcctSessionId, AcctUniqueId, UserName, \
- Realm, NASIPAddress, NASPortId, \
- NASPortType, AcctStartTime, AcctStopTime, \
- AcctSessionTime, AcctAuthentic, ConnectInfo_stop, \
- AcctInputOctets, AcctOutputOctets, CalledStationId, \
- CallingStationId, AcctTerminateCause, ServiceType, \
- FramedProtocol, FramedIPAddress, AcctStopDelay) \
- VALUES(\
- '%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- NULLIF('%{Realm}', ''), \
- '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}', \
- %{%{NAS-Port}:-NULL}, \
- '%{NAS-Port-Type}', \
- ('%S'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval - \
- '%{%{Acct-Session-Time}:-0}'::interval), \
- ('%S'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval), \
- NULLIF('%{Acct-Session-Time}', '')::bigint, \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + \
- '%{%{Acct-Input-Octets}:-0}'::bigint), \
- (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + \
- '%{%{Acct-Output-Octets}:-0}'::bigint), \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Acct-Terminate-Cause}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- NULLIF('%{Framed-IP-Address}', '')::inet, 0)"
- }
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ NULL, \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ NULLIF('%{Framed-IP-Address}', '')::inet)"
}
- }
+ stop {
+ query = "\
+ UPDATE ${....acct_table2} \
+ SET \
+ AcctStopTime = TO_TIMESTAMP(%{integer:Event-Timestamp}), \
+ AcctUpdateTime = TO_TIMESTAMP(%{integer:Event-Timestamp}), \
+ AcctSessionTime = COALESCE(%{%{Acct-Session-Time}:-NULL}, \
+ (%{integer:Event-Timestamp} - EXTRACT(EPOCH FROM(AcctStartTime)))), \
+ AcctInputOctets = (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Input-Octets}:-0}'::bigint), \
+ AcctOutputOctets = (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Output-Octets}:-0}'::bigint), \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
+ ConnectInfo_stop = '%{Connect-Info}' \
+ WHERE ${...session_identifier} \
+ AND AcctStopTime IS NULL"
+
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (${...column_list}) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ NULLIF('%{Realm}', ''), \
+ '%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}}', \
+ %{%{NAS-Port}:-NULL}, \
+ '%{NAS-Port-Type}', \
+ TO_TIMESTAMP(%{integer:Event-Timestamp} - %{%{Acct-Session-Time}:-0}), \
+ TO_TIMESTAMP(%{integer:Event-Timestamp}), \
+ TO_TIMESTAMP(%{integer:Event-Timestamp}), \
+ NULLIF('%{Acct-Session-Time}', '')::bigint, \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ NULL, \
+ (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Input-Octets}:-0}'::bigint), \
+ (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Output-Octets}:-0}'::bigint), \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Acct-Terminate-Cause}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ NULLIF('%{Framed-IP-Address}', '')::inet)"
+
+ # and again where we don't have "AND AcctStopTime IS NULL"
+ query = "\
+ UPDATE ${....acct_table2} \
+ SET \
+ AcctStopTime = TO_TIMESTAMP(%{integer:Event-Timestamp}), \
+ AcctUpdateTime = TO_TIMESTAMP(%{integer:Event-Timestamp}), \
+ AcctSessionTime = COALESCE(%{%{Acct-Session-Time}:-NULL}, \
+ (%{integer:Event-Timestamp} - EXTRACT(EPOCH FROM(AcctStartTime)))), \
+ AcctInputOctets = (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Input-Octets}:-0}'::bigint), \
+ AcctOutputOctets = (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Output-Octets}:-0}'::bigint), \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
+ ConnectInfo_stop = '%{Connect-Info}' \
+ WHERE ${...session_identifier}"
+ }
- #######################################################################
- # Authentication Logging Queries
- #######################################################################
- # postauth_query - Insert some info after authentication
- #######################################################################
-
- post-auth {
- # Write SQL queries to a logfile. This is potentially useful for bulk inserts
- # when used with the rlm_sql_null driver.
-# logfile = ${logdir}/post-auth.sql
-
- query = "\
- INSERT INTO ${..postauth_table} \
- (username, pass, reply, authdate) \
- VALUES(\
- '%{User-Name}', \
- '%{%{User-Password}:-Chap-Password}', \
- '%{reply:Packet-Type}', \
- NOW())"
+ #
+ # No Acct-Status-Type == ignore the packet
+ #
+ none {
+ query = "SELECT true"
+ }
}
+}
+
+
+#######################################################################
+# Authentication Logging Queries
+#######################################################################
+# postauth_query - Insert some info after authentication
+#######################################################################
+
+post-auth {
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
+# logfile = ${logdir}/post-auth.sql
+
+ query = "\
+ INSERT INTO ${..postauth_table} \
+ (username, pass, reply, authdate) \
+ VALUES(\
+ '%{User-Name}', \
+ '%{%{User-Password}:-Chap-Password}', \
+ '%{reply:Packet-Type}', \
+ NOW())"
+}
NASPortId text,
NASPortType text,
AcctStartTime timestamp with time zone,
+ AcctUpdateTime timestamp with time zone,
AcctStopTime timestamp with time zone,
+ AcctInterval bigint,
AcctSessionTime bigint,
AcctAuthentic text,
ConnectInfo_start text,
AcctTerminateCause text,
ServiceType text,
FramedProtocol text,
- FramedIPAddress inet,
- AcctStartDelay integer,
- AcctStopDelay integer
+ FramedIPAddress inet
);
-- This index may be useful..
-- CREATE UNIQUE INDEX radacct_whoson on radacct (AcctStartTime, nasipaddress);
--- For use by onoff-, update-, stop- and simul_* queries
-CREATE INDEX radacct_active_user_idx ON radacct (UserName, NASIPAddress, AcctSessionId) WHERE AcctStopTime IS NULL;
+-- For use by update-, stop- and simul_* queries
+CREATE INDEX radacct_active_session_idx ON radacct (AcctUniqueId) WHERE AcctStopTime IS NULL;
+
+-- Add if you you regularly have to replay packets
+-- CREATE INDEX radacct_session_idx ON radacct (AcctUniqueId);
+
+-- For backwards compatibility
+-- CREATE INDEX radacct_active_user_idx ON radacct (AcctSessionId, UserName, NASIPAddress) WHERE AcctStopTime IS NULL;
+
+-- For use by onoff-
+CREATE INDEX radacct_bulk_close ON radacct (NASIPAddress, AcctStartTime) WHERE AcctStopTime IS NULL;
+
-- and for common statistic queries:
CREATE INDEX radacct_start_user_idx ON radacct (AcctStartTime, UserName);
+
-- and, optionally
-- CREATE INDEX radacct_stop_user_idx ON radacct (acctStopTime, UserName);
# -*- text -*-
-##
-## dialup.conf -- SQLite configuration for default schema (schema.sql)
-##
-## $Id$
+#
+# main/sqlite/queries.conf -- SQLite configuration for default schema (schema.sql)
+#
+# Id: e1e83bf94814ed8be6239977b7bacfed21c0cd6a $
- # Safe characters list for sql queries. Everything else is replaced
- # with their mime-encoded equivalents.
- # The default list should be ok
- #safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"
+# Safe characters list for sql queries. Everything else is replaced
+# with their mime-encoded equivalents.
+# The default list should be ok
+#safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"
- #######################################################################
- # Query config: Username
- #######################################################################
- # This is the username that will get substituted, escaped, and added
- # as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used below
- # everywhere a username substitution is needed so you you can be sure
- # the username passed from the client is escaped properly.
- #
- # Uncomment the next line, if you want the sql_user_name to mean:
- #
- # Use Stripped-User-Name, if it's there.
- # Else use User-Name, if it's there,
- # Else use hard-coded string "DEFAULT" as the user name.
- #sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}}"
- #
- sql_user_name = "%{User-Name}"
+#######################################################################
+# Query config: Username
+#######################################################################
+# This is the username that will get substituted, escaped, and added
+# as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used below
+# everywhere a username substitution is needed so you you can be sure
+# the username passed from the client is escaped properly.
+#
+# Uncomment the next line, if you want the sql_user_name to mean:
+#
+# Use Stripped-User-Name, if it's there.
+# Else use User-Name, if it's there,
+# Else use hard-coded string "DEFAULT" as the user name.
+#sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}}"
+#
+sql_user_name = "%{User-Name}"
- #######################################################################
- # Default profile
- #######################################################################
- # This is the default profile. It is found in SQL by group membership.
- # That means that this profile must be a member of at least one group
- # which will contain the corresponding check and reply items.
- # This profile will be queried in the authorize section for every user.
- # The point is to assign all users a default profile without having to
- # manually add each one to a group that will contain the profile.
- # The SQL module will also honor the User-Profile attribute. This
- # attribute can be set anywhere in the authorize section (ie the users
- # file). It is found exactly as the default profile is found.
- # If it is set then it will *overwrite* the default profile setting.
- # The idea is to select profiles based on checks on the incoming packets,
- # not on user group membership. For example:
- # -- users file --
- # DEFAULT Service-Type == Outbound-User, User-Profile := "outbound"
- # DEFAULT Service-Type == Framed-User, User-Profile := "framed"
- #
- # By default the default_user_profile is not set
- #
- #default_user_profile = "DEFAULT"
+#######################################################################
+# Default profile
+#######################################################################
+# This is the default profile. It is found in SQL by group membership.
+# That means that this profile must be a member of at least one group
+# which will contain the corresponding check and reply items.
+# This profile will be queried in the authorize section for every user.
+# The point is to assign all users a default profile without having to
+# manually add each one to a group that will contain the profile.
+# The SQL module will also honor the User-Profile attribute. This
+# attribute can be set anywhere in the authorize section (ie the users
+# file). It is found exactly as the default profile is found.
+# If it is set then it will *overwrite* the default profile setting.
+# The idea is to select profiles based on checks on the incoming packets,
+# not on user group membership. For example:
+# -- users file --
+# DEFAULT Service-Type == Outbound-User, User-Profile := "outbound"
+# DEFAULT Service-Type == Framed-User, User-Profile := "framed"
+#
+# By default the default_user_profile is not set
+#
+#default_user_profile = "DEFAULT"
- #######################################################################
- # NAS Query
- #######################################################################
- # This query retrieves the radius clients
- #
- # 0. Row ID (currently unused)
- # 1. Name (or IP address)
- # 2. Shortname
- # 3. Type
- # 4. Secret
- # 5. Server
- #######################################################################
+#######################################################################
+# NAS Query
+#######################################################################
+# This query retrieves the radius clients
+#
+# 0. Row ID (currently unused)
+# 1. Name (or IP address)
+# 2. Shortname
+# 3. Type
+# 4. Secret
+# 5. Server
+#######################################################################
- client_query = "SELECT id, nasname, shortname, type, secret, server FROM ${client_table}"
+client_query = "\
+ SELECT id, nasname, shortname, type, secret, server \
+ FROM ${client_table}"
- #######################################################################
- # Authorization Queries
- #######################################################################
- # These queries compare the check items for the user
- # in ${authcheck_table} and setup the reply items in
- # ${authreply_table}. You can use any query/tables
- # you want, but the return data for each row MUST
- # be in the following order:
- #
- # 0. Row ID (currently unused)
- # 1. UserName/GroupName
- # 2. Item Attr Name
- # 3. Item Attr Value
- # 4. Item Attr Operation
- #######################################################################
- # Use these for case sensitive usernames.
-# authorize_check_query = "\
+#######################################################################
+# Authorization Queries
+#######################################################################
+# These queries compare the check items for the user
+# in ${authcheck_table} and setup the reply items in
+# ${authreply_table}. You can use any query/tables
+# you want, but the return data for each row MUST
+# be in the following order:
+#
+# 0. Row ID (currently unused)
+# 1. UserName/GroupName
+# 2. Item Attr Name
+# 3. Item Attr Value
+# 4. Item Attr Operation
+#######################################################################
+
+#
+# Use these for case sensitive usernames.
+#
+#authorize_check_query = "\
# SELECT id, username, attribute, value, op \
# FROM ${authcheck_table} \
# WHERE username = BINARY '%{SQL-User-Name}' \
# ORDER BY id"
-# authorize_reply_query = "\
+#authorize_reply_query = "\
# SELECT id, username, attribute, value, op \
# FROM ${authreply_table} \
# WHERE username = BINARY '%{SQL-User-Name}' \
# ORDER BY id"
- # The default queries are case insensitive. (for compatibility with
- # older versions of FreeRADIUS)
- authorize_check_query = "\
+#
+# The default queries are case insensitive. (for compatibility with older versions of FreeRADIUS)
+#
+authorize_check_query = "\
SELECT id, username, attribute, value, op \
FROM ${authcheck_table} \
WHERE username = '%{SQL-User-Name}' \
ORDER BY id"
- authorize_reply_query = "\
+authorize_reply_query = "\
SELECT id, username, attribute, value, op \
FROM ${authreply_table} \
WHERE username = '%{SQL-User-Name}' \
ORDER BY id"
- # Use these for case sensitive usernames.
-# group_membership_query = "\
+#
+# Use these for case sensitive usernames.
+#
+#group_membership_query = "\
# SELECT groupname \
# FROM ${usergroup_table} \
# WHERE username = BINARY '%{SQL-User-Name}' \
# ORDER BY priority"
- group_membership_query = "\
+group_membership_query = "\
SELECT groupname \
FROM ${usergroup_table} \
WHERE username = '%{SQL-User-Name}' \
ORDER BY priority"
- authorize_group_check_query = "\
+authorize_group_check_query = "\
SELECT id, groupname, attribute, \
Value, op \
FROM ${groupcheck_table} \
WHERE groupname = '%{Sql-Group}' \
ORDER BY id"
- authorize_group_reply_query = "\
+authorize_group_reply_query = "\
SELECT id, groupname, attribute, \
value, op \
FROM ${groupreply_table} \
WHERE groupname = '%{Sql-Group}' \
ORDER BY id"
- #######################################################################
- # Simultaneous Use Checking Queries
- #######################################################################
- # simul_count_query - query for the number of current connections
- # - If this is not defined, no simultaneouls use checking
- # - will be performed by this module instance
- # simul_verify_query - query to return details of current connections
- # for verification
- # - Leave blank or commented out to disable verification step
- # - Note that the returned field order should not be changed.
- #######################################################################
+#######################################################################
+# Simultaneous Use Checking Queries
+#######################################################################
+# simul_count_query - query for the number of current connections
+# - If this is not defined, no simultaneouls use checking
+# - will be performed by this module instance
+# simul_verify_query - query to return details of current connections
+# for verification
+# - Leave blank or commented out to disable verification step
+# - Note that the returned field order should not be changed.
+#######################################################################
- # Uncomment simul_count_query to enable simultaneous use checking
-# simul_count_query = "\
+#
+# Uncomment simul_count_query to enable simultaneous use checking
+#
+#simul_count_query = "\
# SELECT COUNT(*) \
# FROM ${acct_table1} \
# WHERE username = '%{SQL-User-Name}' \
# AND acctstoptime IS NULL"
- simul_verify_query = "\
- SELECT radacctid, acctsessionid, username, \
- nasipaddress, nasportid, framedipaddress, \
- callingstationid, framedprotocol \
+simul_verify_query = "\
+ SELECT radacctid, acctsessionid, username, nasipaddress, nasportid, framedipaddress, \
+ callingstationid, framedprotocol \
FROM ${acct_table1} \
WHERE username = '%{SQL-User-Name}' \
AND acctstoptime IS NULL"
- #######################################################################
- # Accounting and Post-Auth Queries
- #######################################################################
- # These queries insert/update accounting and authentication records.
- # The query to use is determined by the value of 'reference'.
- # This value is used as a configuration path and should resolve to one
- # or more 'query's. If reference points to multiple queries, and a query
- # fails, the next query is executed.
- #
- # Behaviour is identical to the old 1.x/2.x module, except we can now
- # fail between N queries, and query selection can be based on any
- # combination of attributes, or custom 'Acct-Status-Type' values.
- #######################################################################
- accounting {
- reference = "%{tolower:type.%{Acct-Status-Type}.query}"
+#######################################################################
+# Accounting and Post-Auth Queries
+#######################################################################
+# These queries insert/update accounting and authentication records.
+# The query to use is determined by the value of 'reference'.
+# This value is used as a configuration path and should resolve to one
+# or more 'query's. If reference points to multiple queries, and a query
+# fails, the next query is executed.
+#
+# Behaviour is identical to the old 1.x/2.x module, except we can now
+# fail between N queries, and query selection can be based on any
+# combination of attributes, or custom 'Acct-Status-Type' values.
+#######################################################################
+accounting {
+ reference = "%{tolower:type.%{Acct-Status-Type}.query}"
- # Write SQL queries to a logfile. This is potentially useful for bulk inserts
- # when used with the rlm_sql_null driver.
-# logfile = ${logdir}/accounting.sql
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
+# logfile = ${logdir}/accounting.sql
- column_list = "\
- acctsessionid, acctuniqueid, username, \
- realm, nasipaddress, nasportid, \
- nasporttype, acctstarttime, acctupdatetime, \
- acctstoptime, acctsessiontime, acctauthentic, \
- connectinfo_start, connectinfo_stop, acctinputoctets, \
- acctoutputoctets, calledstationid, callingstationid, \
- acctterminatecause, servicetype, framedprotocol, \
- framedipaddress"
+ column_list = "\
+ acctsessionid, acctuniqueid, username, \
+ realm, nasipaddress, nasportid, \
+ nasporttype, acctstarttime, acctupdatetime, \
+ acctstoptime, acctsessiontime, acctauthentic, \
+ connectinfo_start, connectinfo_stop, acctinputoctets, \
+ acctoutputoctets, calledstationid, callingstationid, \
+ acctterminatecause, servicetype, framedprotocol, \
+ framedipaddress"
- type {
- accounting-on {
- #
- # Bulk terminate all sessions associated with a given NAS
- #
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- acctstoptime = %{%{integer:Event-Timestamp}:-NOW()}, \
- acctsessiontime = \
- %{%{integer:Event-Timestamp}:-strftime('%s', NOW())} \
- - strftime('%s', acctstarttime)), \
- acctterminatecause = '%{Acct-Terminate-Cause}' \
- WHERE acctstoptime IS NULL \
- AND nasipaddress = '%{NAS-IP-Address}' \
- AND acctstarttime <= %{integer:Event-Timestamp}"
- }
+ type {
+ accounting-on {
+ #
+ # Bulk terminate all sessions associated with a given NAS
+ #
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ acctstoptime = %{%{integer:Event-Timestamp}:-date('now')}, \
+ acctsessiontime = \
+ %{%{integer:Event-Timestamp}:-strftime('%s', 'now')} \
+ - strftime('%s', acctstarttime)), \
+ acctterminatecause = '%{Acct-Terminate-Cause}' \
+ WHERE acctstoptime IS NULL \
+ AND nasipaddress = '%{NAS-IP-Address}' \
+ AND acctstarttime <= %{integer:Event-Timestamp}"
+ }
- accounting-off {
- query = "${..accounting-on.query}"
- }
+ accounting-off {
+ query = "${..accounting-on.query}"
+ }
- start {
- #
- # Insert a new record into the sessions table
- #
- query = "\
- INSERT INTO ${....acct_table1} \
- (${...column_list}) \
- VALUES \
- ('%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{NAS-Port}', \
- '%{NAS-Port-Type}', \
- %{%{integer:Event-Timestamp}:-NOW()}, \
- %{%{integer:Event-Timestamp}:-NOW()}, \
- NULL, \
- '0', \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- '', \
- '0', \
- '0', \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}')"
+ start {
+ #
+ # Insert a new record into the sessions table
+ #
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (${...column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ %{%{integer:Event-Timestamp}:-date('now')}, \
+ %{%{integer:Event-Timestamp}:-date('now')}, \
+ NULL, \
+ '0', \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ '0', \
+ '0', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}')"
- #
- # Key constraints prevented us from inserting a new session,
- # use the alternate query to update an existing session.
- #
- query = "\
- UPDATE ${....acct_table1} SET \
- acctstarttime = %{%{integer:Event-Timestamp}:-NOW()}, \
- acctupdatetime = %{%{integer:Event-Timestamp}:-NOW()}, \
- connectinfo_start = '%{Connect-Info}' \
- WHERE acctsessionid = '%{Acct-Session-Id}' \
- AND username = '%{SQL-User-Name}' \
- AND nasipaddress = '%{NAS-IP-Address}'"
- }
+ #
+ # Key constraints prevented us from inserting a new session,
+ # use the alternate query to update an existing session.
+ #
+ query = "\
+ UPDATE ${....acct_table1} SET \
+ acctstarttime = %{%{integer:Event-Timestamp}:-date('now')}, \
+ acctupdatetime = %{%{integer:Event-Timestamp}:-date('now'))}, \
+ connectinfo_start = '%{Connect-Info}' \
+ WHERE acctsessionid = '%{Acct-Session-Id}' \
+ AND username = '%{SQL-User-Name}' \
+ AND nasipaddress = '%{NAS-IP-Address}'"
+ }
- interim-update {
- #
- # Update an existing session and calculate the interval
- # between the last data we received for the session and this
- # update. This can be used to find stale sessions.
- #
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- acctupdatetime = %{%{integer:Event-Timestamp}:-NOW()}, \
- acctinterval = 0, \
- framedipaddress = '%{Framed-IP-Address}', \
- acctsessiontime = '%{Acct-Session-Time}', \
- acctinputoctets = %{%{Acct-Input-Gigawords}:-0} \
- << 32 | %{%{Acct-Input-Octets}:-0}, \
- acctoutputoctets = %{%{Acct-Output-Gigawords}:-0} \
- << 32 | %{%{Acct-Output-Octets}:-0} \
- WHERE acctsessionid = '%{Acct-Session-Id}' \
- AND username = '%{SQL-User-Name}' \
- AND nasipaddress = '%{NAS-IP-Address}'"
+ interim-update {
+ #
+ # Update an existing session and calculate the interval
+ # between the last data we received for the session and this
+ # update. This can be used to find stale sessions.
+ #
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ acctupdatetime = %{%{integer:Event-Timestamp}:-date('now')}, \
+ acctinterval = 0, \
+ framedipaddress = '%{Framed-IP-Address}', \
+ acctsessiontime = '%{Acct-Session-Time}', \
+ acctinputoctets = %{%{Acct-Input-Gigawords}:-0} \
+ << 32 | %{%{Acct-Input-Octets}:-0}, \
+ acctoutputoctets = %{%{Acct-Output-Gigawords}:-0} \
+ << 32 | %{%{Acct-Output-Octets}:-0} \
+ WHERE acctsessionid = '%{Acct-Session-Id}' \
+ AND username = '%{SQL-User-Name}' \
+ AND nasipaddress = '%{NAS-IP-Address}'"
- #
- # The update condition matched no existing sessions. Use
- # the values provided in the update to create a new session.
- #
- query = "\
- INSERT INTO ${....acct_table1} \
- (${...column_list}) \
- VALUES \
- ('%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{NAS-Port}', \
- '%{NAS-Port-Type}', \
- (%{%{integer:Event-Timestamp}:-NOW()} - %{%{Acct-Session-Time}:-0}), \
- %{%{integer:Event-Timestamp}:-NOW()}, \
- NULL, \
- '%{Acct-Session-Time}', \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- '', \
- %{%{Acct-Input-Gigawords}:-0} << 32 | \
- %{%{Acct-Input-Octets}:-0}, \
- %{%{Acct-Output-Gigawords}:-0} << 32 | \
- %{%{Acct-Output-Octets}:-0}, \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}')"
- }
+ #
+ # The update condition matched no existing sessions. Use
+ # the values provided in the update to create a new session.
+ #
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (${...column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ (%{%{integer:Event-Timestamp}:-strftime('%s', 'now')} - %{%{Acct-Session-Time}:-0}), \
+ %{%{integer:Event-Timestamp}:-date('now')}, \
+ NULL, \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ %{%{Acct-Input-Gigawords}:-0} << 32 | \
+ %{%{Acct-Input-Octets}:-0}, \
+ %{%{Acct-Output-Gigawords}:-0} << 32 | \
+ %{%{Acct-Output-Octets}:-0}, \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}')"
+ }
- stop {
- #
- # Session has terminated, update the stop time and statistics.
- #
- query = "\
- UPDATE ${....acct_table2} SET \
- acctstoptime = %{%{integer:Event-Timestamp}:-NOW()}, \
- acctsessiontime = '%{Acct-Session-Time}', \
- acctinputoctets = %{%{Acct-Input-Gigawords}:-0} \
- << 32 | %{%{Acct-Input-Octets}:-0}, \
- acctoutputoctets = %{%{Acct-Output-Gigawords}:-0} \
- << 32 | %{%{Acct-Output-Octets}:-0}, \
- acctterminatecause = '%{Acct-Terminate-Cause}', \
- connectinfo_stop = '%{Connect-Info}' \
- WHERE acctsessionid = '%{Acct-Session-Id}' \
- AND username = '%{SQL-User-Name}' \
- AND nasipaddress = '%{NAS-IP-Address}'"
+ stop {
+ #
+ # Session has terminated, update the stop time and statistics.
+ #
+ query = "\
+ UPDATE ${....acct_table2} SET \
+ acctstoptime = %{%{integer:Event-Timestamp}:-date('now')}, \
+ acctsessiontime = '%{Acct-Session-Time}', \
+ acctinputoctets = %{%{Acct-Input-Gigawords}:-0} \
+ << 32 | %{%{Acct-Input-Octets}:-0}, \
+ acctoutputoctets = %{%{Acct-Output-Gigawords}:-0} \
+ << 32 | %{%{Acct-Output-Octets}:-0}, \
+ acctterminatecause = '%{Acct-Terminate-Cause}', \
+ connectinfo_stop = '%{Connect-Info}' \
+ WHERE acctsessionid = '%{Acct-Session-Id}' \
+ AND username = '%{SQL-User-Name}' \
+ AND nasipaddress = '%{NAS-IP-Address}'"
- #
- # The update condition matched no existing sessions. Use
- # the values provided in the update to create a new session.
- #
- query = "\
- INSERT INTO ${....acct_table2} \
- (${...column_list}) \
- VALUES \
- ('%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{NAS-Port}', \
- '%{NAS-Port-Type}', \
- (%{%{integer:Event-Timestamp}:-NOW()} - %{%{Acct-Session-Time}:-0}), \
- %{%{integer:Event-Timestamp}:-NOW()}, \
- %{%{integer:Event-Timestamp}:-NOW()}, \
- '%{Acct-Session-Time}', \
- '%{Acct-Authentic}', \
- '', \
- '%{Connect-Info}', \
- %{%{Acct-Input-Gigawords}:-0} << 32 | \
- %{%{Acct-Input-Octets}:-0}, \
- %{%{Acct-Output-Gigawords}:-0} << 32 | \
- %{%{Acct-Output-Octets}:-0}, \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Acct-Terminate-Cause}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}')"
- }
+ #
+ # The update condition matched no existing sessions. Use
+ # the values provided in the update to create a new session.
+ #
+ query = "\
+ INSERT INTO ${....acct_table2} \
+ (${...column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ %{%{integer:Event-Timestamp}:-strftime('%s', 'now')} - %{%{Acct-Session-Time}:-0}), \
+ %{%{integer:Event-Timestamp}:-date('now')}, \
+ %{%{integer:Event-Timestamp}:-date('now')}, \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', \
+ '', \
+ '%{Connect-Info}', \
+ %{%{Acct-Input-Gigawords}:-0} << 32 | \
+ %{%{Acct-Input-Octets}:-0}, \
+ %{%{Acct-Output-Gigawords}:-0} << 32 | \
+ %{%{Acct-Output-Octets}:-0}, \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Acct-Terminate-Cause}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}')"
}
}
+}
- #######################################################################
- # Authentication Logging Queries
- #######################################################################
- # postauth_query - Insert some info after authentication
- #######################################################################
+#######################################################################
+# Authentication Logging Queries
+#######################################################################
+# postauth_query - Insert some info after authentication
+#######################################################################
- post-auth {
- # Write SQL queries to a logfile. This is potentially useful for bulk inserts
- # when used with the rlm_sql_null driver.
-# logfile = ${logdir}/post-auth.sql
+post-auth {
+ # Write SQL queries to a logfile. This is potentially useful for bulk inserts
+ # when used with the rlm_sql_null driver.
+# logfile = ${logdir}/post-auth.sql
- query = "\
- INSERT INTO ${..postauth_table} \
- (username, pass, reply, authdate) \
- VALUES ( \
- '%{SQL-User-Name}', \
- '%{%{User-Password}:-%{Chap-Password}}', \
- '%{reply:Packet-Type}', \
- '%S')"
- }
+ query = "\
+ INSERT INTO ${..postauth_table} \
+ (username, pass, reply, authdate) \
+ VALUES ( \
+ '%{SQL-User-Name}', \
+ '%{%{User-Password}:-%{Chap-Password}}', \
+ '%{reply:Packet-Type}', \
+ %{%{integer:Event-Timestamp}:-date('now')})"
+}
--- /dev/null
+server:
+ num-threads: 2
--- /dev/null
+info locals
+info args
+thread apply all bt full
+quit
#
else {
update request {
- Acct-Unique-Session-Id := "%{md5:%{User-Name},%{Acct-Session-ID},%{NAS-IP-Address},%{NAS-Identifier},%{NAS-Port-ID},%{NAS-Port}}"
+ Acct-Unique-Session-Id := "%{md5:%{User-Name},%{Acct-Session-ID},%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}},%{NAS-Identifier},%{NAS-Port-ID},%{NAS-Port}}"
}
}
}
handled
}
+#
+# Have the server accept the current request.
+# Can only be called from authorize.
+# Unlike calling the always module instance 'reject' the request will continue to be processed.
+#
+accept.authorize {
+ update control {
+ Auth-Type := accept
+ }
+}
cui.authorize {
if ("%{client:add_cui}" == 'yes') {
update request {
- Chargeable-User-Identity := '\\000'
+ Chargeable-User-Identity := 0x00
}
}
}
cui.pre-proxy {
if (("%{request:Packet-Type}" == 'Access-Request') && ("%{client:add_cui}" == 'yes')) {
update proxy-request {
- Chargeable-User-Identity = '\\000'
+ Chargeable-User-Identity = 0x00
}
}
}
if (!control:Proxy-To-Realm && Chargeable-User-Identity && !reply:Chargeable-User-Identity && \
(Operator-Name || ('${policy.cui_require_operator_name}' != 'yes')) ) {
update reply {
- Chargeable-User-Identity = "%{sha1:${policy.cui_hash_key}%{tolower:%{User-Name}}%{%{Operator-Name}:-}}"
+ Chargeable-User-Identity = "%{sha1:${policy.cui_hash_key}%{tolower:%{User-Name}%{%{Operator-Name}:-}}}"
}
}
+
update reply {
- User-Name -= "%{reply:User-Name}"
+ User-Name !* ANY # remove User-Name from the reply for security
}
+
#
# The section below will store a CUI for the User in the DB.
# You need to configure the cuisql module and your database for this to work.
if (outer.request:Chargeable-User-Identity && \
(outer.request:Operator-Name || ('${policy.cui_require_operator_name}' != 'yes'))) {
update reply {
- Chargeable-User-Identity := "%{sha1:${policy.cui_hash_key}%{tolower:%{User-Name}}%{%{outer.request:Operator-Name}:-}}"
+ Chargeable-User-Identity := "%{sha1:${policy.cui_hash_key}%{tolower:%{User-Name}%{%{outer.request:Operator-Name}:-}}}"
}
}
}
#
-# Forbid all EAP types. Enable this by putting "forbid_eap"
-# into the "authorize" section.
-#
-forbid_eap {
- if (EAP-Message) {
- reject
- }
-}
-
-#
-# Forbid all non-EAP types outside of an EAP tunnel.
-#
-permit_only_eap {
- if (!EAP-Message) {
- # We MAY be inside of a TTLS tunnel.
- # PEAP and EAP-FAST require EAP inside of
- # the tunnel, so this check is OK.
- # If so, then there MUST be an outer EAP message.
- if (!"%{outer.request:EAP-Message}") {
- reject
- }
- }
-}
-
-#
-# Remove Reply-Message from response if were doing EAP
-#
-# Be RFC 3579 2.6.5 compliant - EAP-Message and Reply-Message should
-# not be present in the same response.
-#
-remove_reply_message_if_eap {
- if(reply:EAP-Message && reply:Reply-Message) {
- update reply {
- Reply-Message !* ANY
- }
- }
- else {
- noop
- }
-}
-
-#
# Example of forbidding all attempts to login via
# realms.
#
# what constitutes a user name.
#
filter_username {
+ if (!User-Name) {
+ noop
+ }
+
#
- # reject mixed case
- # e.g. "UseRNaMe"
+ # reject mixed case e.g. "UseRNaMe"
#
- if (User-Name != "%{tolower:%{User-Name}}") {
- reject
- }
+ #if (User-Name != "%{tolower:%{User-Name}}") {
+ # reject
+ #}
#
# reject all whitespace
#
if (User-Name =~ /\\.\\./ ) {
update reply {
- Reply-Message += "Rejected: Username comtains ..s"
+ Reply-Message += "Rejected: Username contains ..s"
}
reject
}
# The following policies are for the Operator-Name
# configuration.
#
-# The policies below can be called as just 'oprator-name' (not
-# oprator-name.authorize etc..) from the various config sections.
+# The policies below can be called as just 'operator-name' (not
+# operator-name.authorize etc..) from the various config sections.
#
# If you require that the Operator-Name be set
# for local clients then call the 'operator-name' policy
# in the authorize section of the virtual-server for your clients in clients.conf
-# to inject an Operator-Name whilst proxying, call the
+# To inject an Operator-Name whilst proxying, call the
# 'operator-name' policy in the pre-proxy section of the virtual server
# No need to call this if you have already enabled this in
# the authorize section.
#
# If the home server does not respond to a request within
# this time, this server will initiate "zombie_period".
+ # The response window can be a number between 0.001 and 60.000
+ # Though values on the low end are discouraged.
#
# The response window is large because responses MAY be slow,
# especially when proxying across the Internet.
# documented in that "man" page. They are only documented here,
# in the comments.
#
-# As of 2.0.0, FreeRADIUS supports a simple processing language
-# in the "authorize", "authenticate", "accounting", etc. sections.
-# See "man unlang" for details.
+# The "unlang" policy language can be used to create complex
+# if / else policies. See "man unlang" for details.
#
prefix = @prefix@
#
pidfile = ${run_dir}/${name}.pid
+# 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 SERVER MUST NOT BE ALLOWED EXECUTE UNTRUSTED PANIC ACTION CODE
+# PATTACH CAN BE USED AS AN ATTACK VECTOR.
+#
+# 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 2>&1 | tee ${logdir}/gdb-${name}-%p.log"
+#
+# 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
#
# msg_goodpass = ""
# msg_badpass = ""
+
+ # The message when the user exceeds the Simultaneous-Use limit.
+ #
+ msg_denied = "You are already logged in - access denied"
}
# The program to execute to do concurrency checks.
# See also raddb/sites-available/status
#
status_server = yes
+
+ #
+ # allow_vulnerable_openssl: Allow the server to start with
+ # versions of OpenSSL known to have critical vulnerabilities.
+ #
+ # This check is based on the version number reported by libssl
+ # and may not reflect patches applied to libssl by
+ # distribution maintainers.
+ #
+ allow_vulnerable_openssl = no
}
# PROXY CONFIGURATION
#
# This is a virtual server that handles DHCP.
#
-# !!!! WARNING !!!!
-#
-# This code is experimental, and SHOULD NOT be used in a
-# production system. It is intended for validation and
-# experimentation ONLY.
-#
-# In order for this to work, you will need to run configure:
-#
-# $ ./configure --with-dhcp
-# $ make
-# $ vi share/dictionary
-#
-# ## Un-comment the line containing $INCLUDE dictionary.dhcp
-# ## Then, save the file.
-#
-# $ make install
-#
-# DHCP is NOT enabled by default.
-#
-# The goal of this effort is to get the code in front of
-# people who are interested in another DHCP server.
-# We NEED FEEDBACK, patches, bug reports, etc. Especially patches!
-#
-# Please contribute, or this work will be nothing more than
-# a curiosity.
-#
-#
-# Q: What does it do?
-# A: It allows the server to receive DHCP packets, and to
-# respond with static, pre-configured DHCP responses.
-#
-# Q: Does it do static/dynamic IP assignment?
-# A: No. Or, maybe. Try it and see.
-#
-# Q: Does it read ISC configuration or lease files?
-# A: No. Please submit patches.
-#
-# Q: Does it have DHCP feature X?
-# A: No. Please submit patches.
-#
-# Q: Does it support option 82?
-# A: Yes.
-#
-# Q: Does it support other options?
-# A: Maybe. See dictionary.dhcp. Please submit patches.
-#
-# Q: It doesn't seem to do much of anything!
-# A: Exactly.
-#
# $Id$
#
######################################################################
# The other only solution is to update FreeRADIUS to use BPF sockets.
#
listen {
+ # This is a dhcp socket.
+ type = dhcp
+
+ # IP address to listen on. Will usually be the IP of the
+ # interface, or 0.0.0.0
ipaddr = 127.0.0.1
+
+ # source IP address for unicast packets sent by the
+ # DHCP server.
+ #
+ # The source IP for unicast packets is chosen from the first
+ # one of the following items which returns a valid IP
+ # address:
+ #
+ # src_ipaddr
+ # ipaddr
+ # reply:DHCP-Server-IP-Address
+ # reply:DHCP-DHCP-Server-Identifier
+ #
+ src_ipaddr = 127.0.0.1
+
+ # The port should be 67 for a production network. Don't set
+ # it to 67 on a production network unless you really know
+ # what you're doing. Even if nothing is configured below, the
+ # server may still NAK legitimate responses from clients.
port = 6700
- type = dhcp
+
+ # Interface name we are listening on. See comments above.
# interface = lo0
# The DHCP server defaults to allowing broadcast packets.
# from a relay agent. i.e. when *no* clients are on the same
# LAN as the DHCP server.
#
- # It's set to "no" here for testing.
+ # It's set to "no" here for testing. It will usually want to
+ # be "yes" in production, unless you are only dealing with
+ # relayed packets.
broadcast = no
# On Linux if you're running the server as non-root, you
# Packets received on the socket will be processed through one
# of the following sections, named after the DHCP packet type.
# See dictionary.dhcp for the packet types.
+
+# Return packets will be sent to, in preference order:
+# DHCP-Gateway-IP-Address
+# DHCP-Client-IP-Address
+# DHCP-Your-IP-Address
+# At least one of these attributes should be set at the end of each
+# section for a response to be sent.
+
dhcp DHCP-Discover {
+
+ # Set the type of packet to send in reply.
+ #
+ # The server will look at the DHCP-Message-Type attribute to
+ # determine which type of packet to send in reply. Common
+ # values would be DHCP-Offer, DHCP-Ack or DHCP-NAK. See
+ # dictionary.dhcp for all the possible values.
+ #
+ # DHCP-Do-Not-Respond can be used to tell the server to not
+ # respond.
+ #
+ # In the event that DHCP-Message-Type is not set then the
+ # server will fall back to determining the type of reply
+ # based on the rcode of this section.
+
update reply {
DHCP-Message-Type = DHCP-Offer
}
# ...
#}
- # Or, allocate IPs from the DHCP pool in SQL.
+ # Or, allocate IPs from the DHCP pool in SQL. You may need to
+ # set the pool name here if you haven't set it elsewhere.
+# update control {
+# Pool-Name := "local"
+# }
# dhcp_sqlippool
+ # If DHCP-Message-Type is not set, returning "ok" or
+ # "updated" from this section will respond with a DHCP-Offer
+ # message.
+ #
+ # Other rcodes will tell the server to not return any response.
ok
}
dhcp DHCP-Request {
+
+ # Response packet type. See DHCP-Discover section above.
update reply {
DHCP-Message-Type = DHCP-Ack
}
# ...
#}
- # Or, allocate IPs from the DHCP pool in SQL.
+ # Or, allocate IPs from the DHCP pool in SQL. You may need to
+ # set the pool name here if you haven't set it elsewhere.
+# update control {
+# Pool-Name := "local"
+# }
# dhcp_sqlippool
+ # If DHCP-Message-Type is not set, returning "ok" or
+ # "updated" from this section will respond with a DHCP-Ack
+ # packet.
+ #
+ # "handled" will not return a packet, all other rcodes will
+ # send back a DHCP-NAK.
ok
}
-# If there's no named section for the packet type, then the packet
-# is processed through this section.
-dhcp {
- # send a DHCP NAK.
+#
+# Other DHCP packet types
+#
+# There should be a separate section for each DHCP message type.
+# By default this configuration will ignore them all. Any packet type
+# not defined here will be responded to with a DHCP-NAK.
+
+dhcp DHCP-Decline {
+ update reply {
+ DHCP-Message-Type = DHCP-Do-Not-Respond
+ }
+ reject
+}
+
+dhcp DHCP-Inform {
+ update reply {
+ DHCP-Message-Type = DHCP-Do-Not-Respond
+ }
+ reject
+}
+
+dhcp DHCP-Release {
+ update reply {
+ DHCP-Message-Type = DHCP-Do-Not-Respond
+ }
reject
}
#
# This lets you perform simple static IP assignment.
#
+# There is a preconfigured "mac2ip" module setup in
+# mods-available/mac2ip. To use it do:
+#
+# # cd raddb/
+# # ln -s ../mods-available/mac2ip mods-enabled/mac2ip
+# # mkdir mods-config/passwd
+#
+# Then create the file mods-config/passwd/mac2ip with the above
+# format.
+#
######################################################################
+
+# This is an example only - see mods-available/mac2ip instead; do
+# not uncomment these lines here.
+#
#passwd mac2ip {
# filename = ${confdir}/mac2ip
# format = "*DHCP-Client-Hardware-Address:=DHCP-Your-IP-Address"
#
# Define the virtual server used to discover dynamic clients.
- dynamic_clients = dynamic_client_server
+ dynamic_clients = dynamic_clients
#
# The directory where client definitions are stored. This
#
# This is the virtual server referenced above by "dynamic_clients".
-server dynamic_client_server {
+server dynamic_clients {
#
# The only contents of the virtual server is the "authorize" section.
# uncomment the section below, otherwise you may want
# to use Chargeable-User-Identity attribute from RFC 4372.
# See further on.
- #update outer.reply {
+ #update outer.reply {
# User-Name = "%{request:User-Name}"
#}
#
# "status" port.
#
# The server statistics are available ONLY on socket of type
-# "status". Qeuries for statistics sent to any other port
+# "status". Queries for statistics sent to any other port
# are ignored.
#
# Similarly, a socket of type "status" will not process
#
# You WILL want to edit this to your local needs. We suggest copying
# the "default" file here, and then editing it. That way, any
-# changes to the 'default" file will not affect this virtual server,
+# changes to the "default" file will not affect this virtual server,
# and vice-versa.
#
# When this virtual server receives the request, the original
Summary: High-performance and highly configurable free RADIUS server
Name: freeradius
-Version: 3.0.1
+Version: 3.0.3
Release: 1%{?dist}
License: GPLv2+ and LGPLv2+
Group: System Environment/Daemons
%endif
%if %{?_with_rlm_sql_oracle:0}%{!?_with_rlm_sql_oracle:1}
rm -rf $RPM_BUILD_ROOT/%{_sysconfdir}/raddb/mods-config/sql/ippool/oracle
+rm -rf $RPM_BUILD_ROOT/%{_sysconfdir}/raddb/mods-config/sql/ippool-dhcp/oracle
rm -rf $RPM_BUILD_ROOT/%{_sysconfdir}/raddb/mods-config/sql/main/oracle
%endif
# remove unsupported config files
rm -f $RPM_BUILD_ROOT/%{_sysconfdir}/raddb/experimental.conf
+rm -rf $RPM_BUILD_ROOT/%{_sysconfdir}/raddb/mods-config/unbound
# install doc files omitted by standard install
for f in COPYRIGHT CREDITS INSTALL.rst README.rst; do
%attr(640,root,radiusd) %config(noreplace) /etc/raddb/clients.conf
%config(noreplace) /etc/raddb/hints
%config(noreplace) /etc/raddb/huntgroups
+%attr(640,root,radiusd) %config(noreplace) /etc/raddb/panic.gdb
%attr(640,root,radiusd) %config(noreplace) /etc/raddb/README.rst
%attr(640,root,radiusd) %config(noreplace) /etc/raddb/proxy.conf
%attr(640,root,radiusd) %config(noreplace) /etc/raddb/radiusd.conf
%doc %{_mandir}/man5/rlm_unix.5.gz
%doc %{_mandir}/man5/unlang.5.gz
%doc %{_mandir}/man5/users.5.gz
-%doc %{_mandir}/man8/radconf2xml.8.gz
%doc %{_mandir}/man8/radcrypt.8.gz
%doc %{_mandir}/man8/raddebug.8.gz
%doc %{_mandir}/man8/radiusd.8.gz
%{_libdir}/freeradius/rlm_chap.so
%{_libdir}/freeradius/rlm_counter.so
%{_libdir}/freeradius/rlm_cram.so
+%{_libdir}/freeradius/rlm_date.so
%{_libdir}/freeradius/rlm_detail.so
%{_libdir}/freeradius/rlm_dhcp.so
%{_libdir}/freeradius/rlm_digest.so
%{_libdir}/freeradius/rlm_sql_sqlite.so
%{_libdir}/freeradius/rlm_sqlcounter.so
%{_libdir}/freeradius/rlm_sqlippool.so
+%{_libdir}/freeradius/rlm_unpack.so
%{_libdir}/freeradius/rlm_unix.so
%{_libdir}/freeradius/rlm_utf8.so
%{_libdir}/freeradius/rlm_wimax.so
%dir %attr(750,root,radiusd) /etc/raddb/mods-config/sql
%dir %attr(750,root,radiusd) /etc/raddb/mods-config/sql/ippool
%dir %attr(750,root,radiusd) /etc/raddb/mods-config/sql/ippool/oracle
+%dir %attr(750,root,radiusd) /etc/raddb/mods-config/sql/ippool-dhcp
+%dir %attr(750,root,radiusd) /etc/raddb/mods-config/sql/ippool-dhcp/oracle
%attr(640,root,radiusd) %config(noreplace) /etc/raddb/mods-config/sql/ippool/oracle/*
+%attr(640,root,radiusd) %config(noreplace) /etc/raddb/mods-config/sql/ippool-dhcp/oracle/*
%dir %attr(750,root,radiusd) /etc/raddb/mods-config/sql/main
%dir %attr(750,root,radiusd) /etc/raddb/mods-config/sql/main/oracle
%attr(640,root,radiusd) %config(noreplace) /etc/raddb/mods-config/sql/main/oracle/*
# delete references to ${BUILD_DIR}/make/include, the "config.mk"
# file adds these dependencies automatically.
# replace "build/" with "${BUILD_DIR}/" when it's in the middle of a line
-#
+#
# remove sequential duplicate lines
-#
+#
# 2) Create empty dependencies from the files
#
# COMMON
# ADD_TARGET_RULE.* - Parameterized "functions" that adds a new target to the
# Makefile. There should be one ADD_TARGET_RULE definition for each
-# type of target that is used in the build.
+# type of target that is used in the build.
#
# New rules can be added by copying one of the existing ones, and
# replacing the line after the "mkdir"
define COMPILE_C_CMDS
$(Q)mkdir -p $(dir $@)
$(Q)$(ECHO) CC $<
- $(Q)$(strip ${COMPILE.c} -o $@ -c -MD ${CFLAGS} ${SRC_CFLAGS} ${INCDIRS} \
+ $(Q)$(strip ${COMPILE.c} -o $@ -c -MD ${CPPFLAGS} ${CFLAGS} ${SRC_CFLAGS} ${INCDIRS} \
${SRC_INCDIRS} ${SRC_DEFS} ${DEFS} $<)
endef
define ANALYZE_C_CMDS
$(Q)mkdir -p $(dir $@)
$(Q)$(ECHO) SCAN $<
- $(Q)$(strip ${ANALYZE.c} --analyze -c $< ${CFLAGS} ${SRC_CFLAGS} ${INCDIRS} \
- ${SRC_INCDIRS} ${SRC_DEFS} ${DEFS}) || (rm -f $@ && false)
+ ${Q}$(strip ${ANALYZE.c} --analyze -Xanalyzer -analyzer-output=html -c $< -o $@ ${CPPFLAGS} \
+ ${CFLAGS} ${SRC_CFLAGS} ${INCDIRS} ${SRC_INCDIRS} ${SRC_DEFS} ${DEFS}) || (rm -f $@ && false)
$(Q)touch $@
endef
# COMPILE_CXX_CMDS - Commands for compiling C++ source code.
define COMPILE_CXX_CMDS
$(Q)mkdir -p $(dir $@)
- $(Q)$(strip ${COMPILE.cxx} -o $@ -c -MD ${CXXFLAGS} ${SRC_CXXFLAGS} ${INCDIRS} \
+ $(Q)$(strip ${COMPILE.cxx} -o $@ -c -MD ${CPPFLAGS} ${CXXFLAGS} ${SRC_CXXFLAGS} ${INCDIRS} \
${SRC_INCDIRS} ${SRC_DEFS} ${DEFS} $<)
endef
$${TGT}_SOURCES :=
$${TGT}_MAN := $${MAN}
$${TGT}_SUFFIX := $$(if $$(suffix $${TGT}),$$(suffix $${TGT}),.exe)
+
+ # If it's an EXE, ensure that transitive library linking works.
+ # i.e. we build libfoo.a which in turn requires -lbar. So, the executable
+ # has to be linked to both libfoo.a and -lbar.
+ ifeq "$${$${TGT}_SUFFIX}" ".exe"
+ $${TGT}_LDLIBS += $$(filter-out %.a %.so %.la,$${$${TGT_PREREQS}_LDLIBS})
+ endif
+
$${TGT}_BUILD := $$(if $$(suffix $${TGT}),$${BUILD_DIR}/lib,$${BUILD_DIR}/bin)
$${TGT}_MAKEFILES += ${1}
$${TGT}_CHECK_HEADERS := $${TGT_CHECK_HEADERS}
# Define the "all" target (which simply builds all user-defined targets) as the
# default goal.
.PHONY: all
-all:
+all:
# Add "clean" rules to remove all build-generated files.
.PHONY: clean
# define LD_LIBRARY_PATH_LOCAL LD_LIBRARY_PATH
#endif
-#if defined(sun)
+#if defined(__sun)
# define SHELL_CMD "/bin/sh"
# define DYNAMIC_LIB_EXT "so"
# define MODULE_LIB_EXT "so"
# define LIBRARIAN "ar"
# define LIBRARIAN_OPTS "cr"
# define RANLIB "ranlib"
-# define PIC_FLAG "-KPIC"
+# define PIC_FLAG "-fPIC"
# define RPATH "-R"
# define SHARED_OPTS "-G"
# define MODULE_OPTS "-G"
va_list ap;
int res;
- va_start( ap, fmt );
- res = vsnprintf( str, n, fmt, ap );
- va_end( ap );
+ va_start(ap, fmt);
+ res = vsnprintf(str, n, fmt, ap);
+ va_end(ap);
return res;
}
#endif
return execvp(argv[0], (char**)argv);
}
else {
- int statuscode;
- waitpid(pid, &statuscode, 0);
- if (WIFEXITED(statuscode)) {
- return WEXITSTATUS(statuscode);
+ int status;
+ waitpid(pid, &status, 0);
+
+ /*
+ * Exited via exit(status)
+ */
+ if (WIFEXITED(status)) {
+ return WEXITSTATUS(status);
}
- return 0;
+
+#ifdef WTERMSIG
+ if (WIFSIGNALED(status)) {
+ return WTERMSIG(status);
+ }
+#endif
+
+ /*
+ * Some other failure.
+ */
+ return 1;
}
}
#endif
${JLIBTOOL}: ${top_makedir}/jlibtool.c
$(Q)mkdir -p $(dir $@)
$(Q)echo CC jlibtool.c
- $(Q)${CC} $< -o $@ ${DARWIN_CFLAGS}
+ $(Q)${CC} $< -o $@
clean: jlibtool_clean
RELINK := local/
# RPATH : flags use to build executables that are installed,
- # with no dependency on the source.
+ # with no dependency on the source.
# RELINL : flags use to build executables that can be run
# from the build directory / source tree.
RPATH_FLAGS := -rpath ${libdir}
RELINK_FLAGS := -rpath $(abspath ${BUILD_DIR})/lib/${RELINK}/.libs
-
+
RELINK_FLAGS_MIN := -rpath ${libdir}
ifneq "${bm_static_libs}" "yes"
t) timeout="$OPTARG"
[ "$timeout" = "0" ] && timeout=1000000
;;
- u) condition="(User-Name == $OPTARG)"
+ u) condition="(User-Name == '$OPTARG')"
;;
?) usage
;;
# Debug to a file, and then tell us where the file is.
#
outfile=`$radmin -e "debug file radmin.debug.$$" -e "show debug file"`
-group=`$radmin -e "debug file radmin.debug.$$" -e "show config group"`
+group=`$radmin -e "debug file radmin.debug.$$" -e "show config security.group"`
#
# If there was an error setting the debug output, re-set the
#
# $Id$
#
-.PHONY: format
#
# This should only be run by hand, and then sanity checked by hand!
#
-format: dictionary*
- @for x in dictionary* ; do \
- cat $$x | ./format.pl > tmp; \
- mv tmp $$x; \
+format: $(wildcard dictionary*)
+ @for x in $(wildcard dictionary*) ; do \
+ ./format.pl $$x; \
done
$INCLUDE dictionary.3gpp2
$INCLUDE dictionary.acc
$INCLUDE dictionary.acme
+$INCLUDE dictionary.actelis
$INCLUDE dictionary.airespace
$INCLUDE dictionary.alcatel
$INCLUDE dictionary.alcatel.sr
$INCLUDE dictionary.ascend
$INCLUDE dictionary.bay
$INCLUDE dictionary.bintec
+$INCLUDE dictionary.bluecoat
$INCLUDE dictionary.broadsoft
+$INCLUDE dictionary.brocade
$INCLUDE dictionary.bskyb
$INCLUDE dictionary.bt
$INCLUDE dictionary.cablelabs
$INCLUDE dictionary.camiant
$INCLUDE dictionary.chillispot
$INCLUDE dictionary.cisco
+$INCLUDE dictionary.cisco.asa
#
-# The Cisco VPN300 dictionary is the same as the altiga one.
+# The Cisco VPN300 dictionary uses the same Vendor ID as the ASA one.
# You shouldn't use both at the same time.
#
+# Note : the altiga dictionary, not listed here, also uses the same Vendor ID
+#
#$INCLUDE dictionary.cisco.vpn3000
$INCLUDE dictionary.cisco.vpn5000
$INCLUDE dictionary.cisco.bbsm
$INCLUDE dictionary.eltex
$INCLUDE dictionary.epygi
$INCLUDE dictionary.erx
+$INCLUDE dictionary.equallogic
$INCLUDE dictionary.ericsson
+$INCLUDE dictionary.ericsson.packet.core.networks
$INCLUDE dictionary.extreme
$INCLUDE dictionary.f5
$INCLUDE dictionary.fdxtended
$INCLUDE dictionary.xylan
$INCLUDE dictionary.yubico
$INCLUDE dictionary.zeus
+$INCLUDE dictionary.zte
$INCLUDE dictionary.zyxel
-# DHCP dictionary for DHCP functionality and use of dhcp module
-$INCLUDE dictionary.dhcp
-
-# VQP dictionary for VMPS functionality and use of vmps module
-$INCLUDE dictionary.vqp
-
#
# And finally the server internal attributes.
# These are attributes which NEVER go into a RADIUS packet.
--- /dev/null
+# -*- text -*-
+# Copyright (C) 2014 The FreeRADIUS Server project and contributors
+##############################################################################
+#
+# Actelis dictionary
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR Actelis 5468
+
+BEGIN-VENDOR Actelis
+
+ATTRIBUTE Actelis-Privilege 1 string
+
+END-VENDOR Actelis
# -*- text -*-
-# Copyright (C) 2011 The FreeRADIUS Server project and contributors
+# Copyright (C) 2014 The FreeRADIUS Server project and contributors
+#
# Altiga vendor attributes
#
+# Altiga networks was aquired by Cisco in 2000.
+#
# $Id$
#
ATTRIBUTE Altiga-L2TP-Min-Authentication-G/U 19 integer
ATTRIBUTE Altiga-PPTP-Encryption-G 20 integer
ATTRIBUTE Altiga-L2TP-Encryption-G 21 integer
+ATTRIBUTE Altiga-Argument-Authentication-Server-Type 22 integer
ATTRIBUTE Altiga-IPSec-L2L-Keepalives-G 25 integer
+ATTRIBUTE Altiga-Argument-IPSec-Group-Name 26 integer
ATTRIBUTE Altiga-IPSec-Split-Tunnel-List-G 27 string
ATTRIBUTE Altiga-IPSec-Default-Domain-G 28 string
ATTRIBUTE Altiga-IPSec-Secondary-Domains-G 29 string
ATTRIBUTE Altiga-IPSec-Tunnel-Type-G 30 integer
ATTRIBUTE Altiga-IPSec-Mode-Config-G 31 integer
+ATTRIBUTE Altiga-Argument-Authentication-Server-Priority 32 integer
ATTRIBUTE Altiga-IPSec-User-Group-Lock-G 33 integer
ATTRIBUTE Altiga-IPSec-Over-NAT-G 34 integer
ATTRIBUTE Altiga-IPSec-Over-NAT-Port-Num-G 35 integer
+ATTRIBUTE Altiga-Partitioning-Primary-DHCP 128 ipaddr
+ATTRIBUTE Altiga-Partitioning-Secondary-DHCP 129 ipaddr
+ATTRIBUTE Altiga-Partitioning-Premise-Rout 131 ipaddr
+ATTRIBUTE Altiga-Partitioning-Partition-Max-Sessions 132 string
+ATTRIBUTE Altiga-Partitioning-Mobile-IP-Key 133 string
+ATTRIBUTE Altiga-Partitioning-Mobile-IP-Address 134 ipaddr
+ATTRIBUTE Altiga-Partitioning-Mobile-IP-SPI 135 ipaddr
+ATTRIBUTE Altiga-Partitioning-Strip-Realm 136 integer
+ATTRIBUTE Altiga-Partitioning-Group 137 integer
+ATTRIBUTE Altiga-Group-Name 250 string
# Altiga value
VALUE Altiga-Allow-Alpha-Only-Passwords-G Allow 1
VALUE Altiga-L2TP-Encryption-G L2TP-40/128-Stateless-Req 14
VALUE Altiga-L2TP-Encryption-G L2TP-40/128-Enc/Statls-Req 15
+VALUE Altiga-Argument-Authentication-Server-Type FirstActiveServer 1
+VALUE Altiga-Argument-Authentication-Server-Type RADIUS 1
+VALUE Altiga-Argument-Authentication-Server-Type LDAP 2
+VALUE Altiga-Argument-Authentication-Server-Type NT 3
+VALUE Altiga-Argument-Authentication-Server-Type SDI 4
+VALUE Altiga-Argument-Authentication-Server-Type Internal 5
+
VALUE Altiga-IPSec-L2L-Keepalives-G ON 1
VALUE Altiga-IPSec-L2L-Keepalives-G OFF 0
VALUE Altiga-IPSec-Over-NAT-G ON 1
VALUE Altiga-IPSec-Over-NAT-G OFF 0
+VALUE Altiga-Partitioning-Strip-Realm ON 1
+VALUE Altiga-Partitioning-Strip-Realm OFF 0
+
END-VENDOR Altiga
--- /dev/null
+# -*- text -*-
+# Copyright (C) 2014 The FreeRADIUS Server project and contributors
+#
+# Blue Coat Dictionary
+#
+# See also dictionary.packeteer for former Packeteer products.
+#
+
+VENDOR BlueCoat 14501
+
+BEGIN-VENDOR BlueCoat
+
+ATTRIBUTE Blue-Coat-Group 1 string
+# Accepts multiple groups as comma-separated list.
+
+ATTRIBUTE Blue-Coat-Authorization 2 integer
+
+VALUE Blue-Coat-Authorization No-Access 0
+VALUE Blue-Coat-Authorization Read-Only-Access 1
+VALUE Blue-Coat-Authorization Read-Write-Access 2
+
+END-VENDOR BlueCoat
--- /dev/null
+# -*- text -*-
+# Copyright (C) 2014 The FreeRADIUS Server project and contributors
+#
+VENDOR Brocade 1588
+BEGIN-VENDOR Brocade
+
+ATTRIBUTE Brocade-Auth-Role 1 string
+# Valid attribute values:
+# Admin BasicSwitchAdmin FabricAdmin Operator
+# SecurityAdmin SwitchAdmin User ZoneAdmin
+
+ATTRIBUTE Brocade-AVPairs1 2 string
+ATTRIBUTE Brocade-AVPairs2 3 string
+ATTRIBUTE Brocade-AVPairs3 4 string
+ATTRIBUTE Brocade-AVPairs4 5 string
+# Brocade-AVPairs1/2/3/4:
+# Optional, specifies Admin Domain or Virtual Fabric List
+
+ATTRIBUTE Brocade-Passwd-ExpiryDate 6 string # Format: MM/DD/YYYY
+ATTRIBUTE Brocade-Passwd-WarnPeriod 7 string # Format: integer in days
+
+END-VENDOR Brocade
+
ATTRIBUTE Cisco-Control-Info 253 string
ATTRIBUTE Cisco-Xmit-Rate 255 integer
+VALUE Cisco-Disconnect-Cause No-Reason 0
+VALUE Cisco-Disconnect-Cause No-Disconnect 1
VALUE Cisco-Disconnect-Cause Unknown 2
+VALUE Cisco-Disconnect-Cause Call-Disconnect 3
VALUE Cisco-Disconnect-Cause CLID-Authentication-Failure 4
+VALUE Cisco-Disconnect-Cause No-Modem-Available 9
VALUE Cisco-Disconnect-Cause No-Carrier 10
VALUE Cisco-Disconnect-Cause Lost-Carrier 11
VALUE Cisco-Disconnect-Cause No-Detected-Result-Codes 12
VALUE Cisco-Disconnect-Cause Raw-TCP-Disabled 26
VALUE Cisco-Disconnect-Cause Control-C-Detected 27
VALUE Cisco-Disconnect-Cause EXEC-Program-Destroyed 28
+VALUE Cisco-Disconnect-Cause Close-Virtual-Connection 29
+VALUE Cisco-Disconnect-Cause End-Virtual-Connection 30
+VALUE Cisco-Disconnect-Cause Exit-Rlogin 31
+VALUE Cisco-Disconnect-Cause Invalid-Rlogin-Option 32
+VALUE Cisco-Disconnect-Cause Insufficient-Resources 33
VALUE Cisco-Disconnect-Cause Timeout-PPP-LCP 40
VALUE Cisco-Disconnect-Cause Failed-PPP-LCP-Negotiation 41
VALUE Cisco-Disconnect-Cause Failed-PPP-PAP-Auth-Fail 42
VALUE Cisco-Disconnect-Cause Failed-PPP-Remote-Auth 44
VALUE Cisco-Disconnect-Cause PPP-Remote-Terminate 45
VALUE Cisco-Disconnect-Cause PPP-Closed-Event 46
+VALUE Cisco-Disconnect-Cause NCP-Closed-PPP 47
+VALUE Cisco-Disconnect-Cause MP-Error-PPP 48
+VALUE Cisco-Disconnect-Cause PPP-Maximum-Channels 49
+VALUE Cisco-Disconnect-Cause Tables-Full 50
+VALUE Cisco-Disconnect-Cause Resources-Full 51
+VALUE Cisco-Disconnect-Cause Invalid-IP-Address 52
+VALUE Cisco-Disconnect-Cause Bad-Hostname 53
+VALUE Cisco-Disconnect-Cause Bad-Port 54
+VALUE Cisco-Disconnect-Cause Reset-TCP 60
+VALUE Cisco-Disconnect-Cause TCP-Connection-Refused 61
+VALUE Cisco-Disconnect-Cause Timeout-TCP 62
+VALUE Cisco-Disconnect-Cause Foreign-Host-Close-TCP 63
+VALUE Cisco-Disconnect-Cause TCP-Network-Unreachable 64
+VALUE Cisco-Disconnect-Cause TCP-Host-Unreachable 65
+VALUE Cisco-Disconnect-Cause TCP-Network-Admin-Unreachable 66
+VALUE Cisco-Disconnect-Cause TCP-Port-Unreachable 67
VALUE Cisco-Disconnect-Cause Session-Timeout 100
VALUE Cisco-Disconnect-Cause Session-Failed-Security 101
VALUE Cisco-Disconnect-Cause Session-End-Callback 102
VALUE Cisco-Disconnect-Cause Invalid-Protocol 120
+VALUE Cisco-Disconnect-Cause RADIUS-Disconnect 150
+VALUE Cisco-Disconnect-Cause Local-Admin-Disconnect 151
+VALUE Cisco-Disconnect-Cause SNMP-Disconnect 152
+VALUE Cisco-Disconnect-Cause V110-Retries 160
+VALUE Cisco-Disconnect-Cause PPP-Authentication-Timeout 170
+VALUE Cisco-Disconnect-Cause Local-Hangup 180
+VALUE Cisco-Disconnect-Cause Remote-Hangup 185
+VALUE Cisco-Disconnect-Cause T1-Quiesced 190
+VALUE Cisco-Disconnect-Cause Call-Duration 195
+VALUE Cisco-Disconnect-Cause VPN-User-Disconnect 600
+VALUE Cisco-Disconnect-Cause VPN-Carrier-Loss 601
+VALUE Cisco-Disconnect-Cause VPN-No-Resources 602
+VALUE Cisco-Disconnect-Cause VPN-Bad-Control-Packet 603
+VALUE Cisco-Disconnect-Cause VPN-Admin-Disconnect 604
+VALUE Cisco-Disconnect-Cause VPN-Tunnel-Shut 605
+VALUE Cisco-Disconnect-Cause VPN-Local-Disconnect 606
+VALUE Cisco-Disconnect-Cause VPN-Session-Limit 607
+VALUE Cisco-Disconnect-Cause VPN-Call-Redirect 608
END-VENDOR Cisco
--- /dev/null
+# -*- text -*-
+# Copyright (C) 2013 The FreeRADIUS Server project and contributors
+#
+# Cisco Adaptative Security Appliance (ASA) Dictionary
+#
+# http://www.cisco.com/en/US/docs/security/asa/asa90/configuration/guide/ref_extserver.html#wp1802187
+#
+# $Id$
+#
+
+VENDOR Cisco-ASA 3076
+
+BEGIN-VENDOR Cisco-ASA
+
+ATTRIBUTE ASA-Simultaneous-Logins 2 integer
+ATTRIBUTE ASA-Primary-DNS 5 string
+ATTRIBUTE ASA-Secondary-DNS 6 string
+ATTRIBUTE ASA-Primary-WINS 7 string
+ATTRIBUTE ASA-Secondary-WINS 8 string
+ATTRIBUTE ASA-SEP-Card-Assignment 9 integer
+ATTRIBUTE ASA-Tunneling-Protocols 11 integer
+ATTRIBUTE ASA-IPsec-Sec-Association 12 string
+ATTRIBUTE ASA-IPsec-Authentication 13 integer
+ATTRIBUTE ASA-Banner1 15 string
+ATTRIBUTE ASA-IPsec-Allow-Passwd-Store 16 integer
+ATTRIBUTE ASA-Use-Client-Address 17 integer
+ATTRIBUTE ASA-PPTP-Encryption 20 integer
+ATTRIBUTE ASA-L2TP-Encryption 21 integer
+ATTRIBUTE ASA-Group-Policy 25 string
+ATTRIBUTE ASA-IPsec-Split-Tunnel-List 27 string
+ATTRIBUTE ASA-IPsec-Default-Domain 28 string
+ATTRIBUTE ASA-IPsec-Split-DNS-Names 29 string
+ATTRIBUTE ASA-IPsec-Tunnel-Type 30 integer
+ATTRIBUTE ASA-IPsec-Mode-Config 31 integer
+ATTRIBUTE ASA-IPsec-Over-UDP 34 integer
+ATTRIBUTE ASA-IPsec-Over-UDP-Port 35 integer
+ATTRIBUTE ASA-Banner2 36 string
+ATTRIBUTE ASA-PPTP-MPPC-Compression 37 integer
+ATTRIBUTE ASA-L2TP-MPPC-Compression 38 integer
+ATTRIBUTE ASA-IPsec-IP-Compression 39 integer
+ATTRIBUTE ASA-IPsec-IKE-Peer-ID-Check 40 integer
+ATTRIBUTE ASA-IKE-Keep-Alives 41 integer
+ATTRIBUTE ASA-IPsec-Auth-On-Rekey 42 integer
+ATTRIBUTE ASA-Required-Client-Firewall-Vendor-Code 45 integer
+ATTRIBUTE ASA-Required-Client-Firewall-Product-Code 46 integer
+ATTRIBUTE ASA-Required-Client-Firewall-Description 47 string
+ATTRIBUTE ASA-Require-HW-Client-Auth 48 integer
+ATTRIBUTE ASA-Required-Individual-User-Auth 49 integer
+ATTRIBUTE ASA-Authenticated-User-Idle-Timeout 50 integer
+ATTRIBUTE ASA-Cisco-IP-Phone-Bypass 51 integer
+ATTRIBUTE ASA-IPsec-Split-Tunneling-Policy 55 integer
+ATTRIBUTE ASA-IPsec-Required-Client-Firewall-Capability 56 integer
+ATTRIBUTE ASA-IPsec-Client-Firewall-Filter-Name 57 string
+ATTRIBUTE ASA-IPsec-Client-Firewall-Filter-Optional 58 integer
+ATTRIBUTE ASA-IPsec-Backup-Servers 59 integer
+ATTRIBUTE ASA-IPsec-Backup-Server-List 60 string
+ATTRIBUTE ASA-DHCP-Network-Scope 61 string
+ATTRIBUTE ASA-Intercept-DHCP-Configure-Msg 62 integer
+ATTRIBUTE ASA-MS-Client-Subnet-Mask 63 integer
+ATTRIBUTE ASA-Allow-Network-Extension-Mode 64 integer
+ATTRIBUTE ASA-Authorization-Type 65 integer
+ATTRIBUTE ASA-Authorization-Required 66 integer
+ATTRIBUTE ASA-Authorization-DN-Field 67 string
+ATTRIBUTE ASA-Authorization-DN-Field 67 string
+ATTRIBUTE ASA-IKE-KeepAlive-Confidence-Interval 68 integer
+ATTRIBUTE ASA-WebVPN-Content-Filter-Parameters 69 integer
+ATTRIBUTE ASA-WebVPN-HTML-Filter 69 integer
+ATTRIBUTE ASA-WebVPN-URL-List 71 string
+ATTRIBUTE ASA-WebVPN-Port-Forwarding-List 72 string
+ATTRIBUTE ASA-WebVPN-Access-List 73 string
+ATTRIBUTE ASA-WebVPNACL 73 string
+ATTRIBUTE ASA-WebVPN-HTTP-Proxy-IP-Address 74 string
+ATTRIBUTE ASA-Cisco-LEAP-Bypass 75 integer
+ATTRIBUTE ASA-WebVPN-Default-Homepage 76 string
+ATTRIBUTE ASA-Client-Type-Version-Limiting 77 string
+ATTRIBUTE ASA-WebVPN-Group-based-HTTP/HTTPS-Proxy-Exception-List 78 string
+ATTRIBUTE ASA-WebVPN-Port-Forwarding-Name 79 string
+ATTRIBUTE ASA-IE-Proxy-Server 80 string
+ATTRIBUTE ASA-IE-Proxy-Server-Policy 81 integer
+ATTRIBUTE ASA-IE-Proxy-Exception-List 82 string
+ATTRIBUTE ASA-IE-Proxy-Bypass-Local 83 integer
+ATTRIBUTE ASA-IKE-Keepalive-Retry-Interval 84 integer
+ATTRIBUTE ASA-Tunnel-Group-Lock 85 string
+ATTRIBUTE ASA-Access-List-Inbound 86 string
+ATTRIBUTE ASA-Access-List-Outbound 87 string
+ATTRIBUTE ASA-Perfect-Forward-Secrecy-Enable 88 integer
+ATTRIBUTE ASA-NAC-Enable 89 integer
+ATTRIBUTE ASA-NAC-Status-Query-Timer 90 integer
+ATTRIBUTE ASA-NAC-Revalidation-Timer 91 integer
+ATTRIBUTE ASA-NAC-Default-ACL 92 string
+ATTRIBUTE ASA-WebVPN-URL-Entry-Enable 93 integer
+ATTRIBUTE ASA-WebVPN-File-Access-Enable 94 integer
+ATTRIBUTE ASA-WebVPN-File-Server-Entry-Enable 95 integer
+ATTRIBUTE ASA-WebVPN-File-Server-Browsing-Enable 96 integer
+ATTRIBUTE ASA-WebVPN-Port-Forwarding-Enable 97 integer
+ATTRIBUTE ASA-WebVPN-Port-Forwarding-Exchange-Proxy-Enable 98 integer
+ATTRIBUTE ASA-WebVPN-Port-Forwarding-HTTP-Proxy 99 integer
+ATTRIBUTE ASA-WebVPN-Citrix-Metaframe-Enable 101 integer
+ATTRIBUTE ASA-WebVPN-Apply-ACL 102 integer
+ATTRIBUTE ASA-WebVPN-SSL-VPN-Client-Enable 103 integer
+ATTRIBUTE ASA-WebVPN-SSL-VPN-Client-Required 104 integer
+ATTRIBUTE ASA-WebVPN-SSL-VPN-Client-Keep-Installation 105 integer
+ATTRIBUTE ASA-SVC-Keepalive 107 integer
+ATTRIBUTE ASA-WebVPN-SVC-Keepalive-Frequency 107 integer
+ATTRIBUTE ASA-SVC-DPD-Interval-Client 108 integer
+ATTRIBUTE ASA-WebVPN-SVC-Client-DPD-Frequency 108 integer
+ATTRIBUTE ASA-SVC-DPD-Interval-Gateway 109 integer
+ATTRIBUTE ASA-WebVPN-SVC-Gateway-DPD-Frequency 109 integer
+ATTRIBUTE ASA-SVC-Rekey-Time 110 integer
+ATTRIBUTE ASA-WebVPN-SVC-Rekey-Time 110 integer
+ATTRIBUTE ASA-WebVPN-SVC-Rekey-Method 111 integer
+ATTRIBUTE ASA-WebVPN-SVC-Compression 112 integer
+ATTRIBUTE ASA-WebVPN-Customization 113 string
+ATTRIBUTE ASA-WebVPN-SSO-Server-Name 114 string
+ATTRIBUTE ASA-WebVPN-Deny-Message 116 string
+ATTRIBUTE ASA-WebVPN-HTTP-Compression 120 integer
+ATTRIBUTE ASA-WebVPN-Keepalive-Ignore 121 integer
+ATTRIBUTE ASA-Extended-Authentication-On-Rekey 122 integer
+ATTRIBUTE ASA-SVC-DTLS 123 integer
+ATTRIBUTE ASA-WebVPN-SVC-DTLS-Enable 123 integer
+ATTRIBUTE ASA-WebVPN-Auto-HTTP-Signon 124 string
+ATTRIBUTE ASA-SVC-MTU 125 integer
+ATTRIBUTE ASA-WebVPN-SVC-DTLS-MTU 125 integer
+ATTRIBUTE ASA-WebVPN-Hidden-Shares 126 integer
+ATTRIBUTE ASA-SVC-Modules 127 string
+ATTRIBUTE ASA-SVC-Profiles 128 string
+ATTRIBUTE ASA-SVC-Ask 131 integer
+ATTRIBUTE ASA-SVC-Ask-Timeout 132 integer
+ATTRIBUTE ASA-IE-Proxy-PAC-URL 133 string
+ATTRIBUTE ASA-Strip-Realm 135 integer
+ATTRIBUTE ASA-Smart-Tunnel 136 string
+ATTRIBUTE ASA-WebVPN-Smart-Tunnel 136 string
+ATTRIBUTE ASA-WebVPN-ActiveX-Relay 137 integer
+ATTRIBUTE ASA-Smart-Tunnel-Auto 138 integer
+ATTRIBUTE ASA-WebVPN-Smart-Tunnel-Auto-Start 138 integer
+ATTRIBUTE ASA-Smart-Tunnel-Auto-Signon-Enable 139 string
+ATTRIBUTE ASA-WebVPN-Smart-Tunnel-Auto-Sign-On 139 string
+ATTRIBUTE ASA-VLAN 140 integer
+ATTRIBUTE ASA-NAC-Settings 141 string
+ATTRIBUTE ASA-Member-Of 145 string
+ATTRIBUTE ASA-TunnelGroupName 146 string
+ATTRIBUTE ASA-WebVPN-Idle-Timeout-Alert-Interval 148 integer
+ATTRIBUTE ASA-WebVPN-Session-Timeout-Alert-Interval 149 integer
+ATTRIBUTE ASA-ClientType 150 integer
+ATTRIBUTE ASA-SessionType 151 integer
+ATTRIBUTE ASA-SessionSubtype 152 integer
+ATTRIBUTE ASA-WebVPN-Download_Max-Size 157 integer
+ATTRIBUTE ASA-WebVPN-Upload-Max-Size 158 integer
+ATTRIBUTE ASA-WebVPN-Post-Max-Size 159 integer
+ATTRIBUTE ASA-WebVPN-User-Storage 160 string
+ATTRIBUTE ASA-WebVPN-Storage-Objects 161 string
+ATTRIBUTE ASA-WebVPN-Storage-Key 162 string
+ATTRIBUTE ASA-WebVPN-VDI 163 string
+ATTRIBUTE ASA-Address-Pools 217 string
+ATTRIBUTE ASA-IPv6-Address-Pools 218 string
+ATTRIBUTE ASA-IPv6-VPN-Filter 219 string
+ATTRIBUTE ASA-Privilege-Level 220 integer
+ATTRIBUTE ASA-WebVPN-UNIX-User-ID 221 integer
+ATTRIBUTE ASA-WebVPN-UNIX-Group-ID 222 integer
+ATTRIBUTE ASA-WebVPN-Macro-Substitution-Value1 223 string
+ATTRIBUTE ASA-WebVPN-Macro-Substitution-Value2 224 string
+ATTRIBUTE ASA-WebVPNSmart-Card-Removal-Disconnect 225 integer
+ATTRIBUTE ASA-WebVPN-Smart-Tunnel-Tunnel-Policy 227 string
+ATTRIBUTE ASA-WebVPN-Home-Page-Use-Smart-Tunnel 228 integer
+
+VALUE ASA-Authorization-Required No 0
+VALUE ASA-Authorization-Required Yes 1
+
+VALUE ASA-Authorization-Type None 0
+VALUE ASA-Authorization-Type Radius 1
+VALUE ASA-Authorization-Type LDAP 2
+
+VALUE ASA-Cisco-IP-Phone-Bypass Disabled 0
+VALUE ASA-Cisco-IP-Phone-Bypass Enabled 1
+
+VALUE ASA-Cisco-LEAP-Bypass Disabled 0
+VALUE ASA-Cisco-LEAP-Bypass Enabled 1
+
+VALUE ASA-ClientType Cisco-VPN-Client-IKEv1 1
+VALUE ASA-ClientType AnyConnect-Client-SSL-VPN 2
+VALUE ASA-ClientType Clientless-SSL-VPN 3
+VALUE ASA-ClientType Cut-Through-Proxy 4
+VALUE ASA-ClientType L2TP/IPsec-SSL-VPN 5
+VALUE ASA-ClientType AnyConnect-Client-IPSec-VPN-IKEv2 6
+
+VALUE ASA-Extended-Authentication-On-Rekey Disabled 0
+VALUE ASA-Extended-Authentication-On-Rekey Enabled 1
+
+VALUE ASA-IE-Proxy-Bypass-Local None 0
+VALUE ASA-IE-Proxy-Bypass-Local Local 1
+
+VALUE ASA-IE-Proxy-Server-Policy No-Modify 1
+VALUE ASA-IE-Proxy-Server-Policy No-Proxy 2
+VALUE ASA-IE-Proxy-Server-Policy Auto-detect 3
+VALUE ASA-IE-Proxy-Server-Policy Use-Concentrator-Setting 4
+
+VALUE ASA-IKE-Keep-Alives Disabled 0
+VALUE ASA-IKE-Keep-Alives Enabled 1
+
+VALUE ASA-Allow-Network-Extension-Mode Disabled 0
+VALUE ASA-Allow-Network-Extension-Mode Enabled 1
+
+VALUE ASA-Intercept-DHCP-Configure-Msg Disabled 0
+VALUE ASA-Intercept-DHCP-Configure-Msg Enabled 1
+
+VALUE ASA-IPsec-Allow-Passwd-Store Disabled 0
+VALUE ASA-IPsec-Allow-Passwd-Store Enabled 1
+
+VALUE ASA-IPsec-Authentication None 0
+VALUE ASA-IPsec-Authentication RADIUS 1
+VALUE ASA-IPsec-Authentication LDAP-Authorization-only 2
+VALUE ASA-IPsec-Authentication NT-Domain 3
+VALUE ASA-IPsec-Authentication SDI 4
+VALUE ASA-IPsec-Authentication Internal 5
+VALUE ASA-IPsec-Authentication RADIUS-with-Expiry 6
+VALUE ASA-IPsec-Authentication Kerberos/Active-Directory 7
+
+VALUE ASA-IPsec-Auth-On-Rekey Disabled 0
+VALUE ASA-IPsec-Auth-On-Rekey Enabled 1
+
+VALUE ASA-IPsec-Backup-Servers Use-Client-Configured-List 1
+VALUE ASA-IPsec-Backup-Servers Disable-and-clear-client-list 2
+VALUE ASA-IPsec-Backup-Servers Use-Backup-Server-List 3
+
+VALUE ASA-IPsec-Client-Firewall-Filter-Optional Required 0
+VALUE ASA-IPsec-Client-Firewall-Filter-Optional Optional 1
+
+VALUE ASA-IPsec-IKE-Peer-ID-Check Required 1
+VALUE ASA-IPsec-IKE-Peer-ID-Check If-Supported-By-Peer-Certificate 2
+VALUE ASA-IPsec-IKE-Peer-ID-Check Do-Not-Check 3
+
+VALUE ASA-IPsec-IP-Compression Disabled 0
+VALUE ASA-IPsec-IP-Compression Enabled 1
+
+VALUE ASA-IPsec-Mode-Config Disabled 0
+VALUE ASA-IPsec-Mode-Config Enabled 1
+
+VALUE ASA-IPsec-Over-UDP Disabled 0
+VALUE ASA-IPsec-Over-UDP Enabled 1
+
+VALUE ASA-IPsec-Required-Client-Firewall-Capability None 0
+VALUE ASA-IPsec-Required-Client-Firewall-Capability Policy-Remotely-Defined 1
+VALUE ASA-IPsec-Required-Client-Firewall-Capability Policy-Pushed 2
+VALUE ASA-IPsec-Required-Client-Firewall-Capability Policy-from-Server 4
+
+VALUE ASA-IPsec-Split-Tunneling-Policy No-Split-Tunneling 0
+VALUE ASA-IPsec-Split-Tunneling-Policy Split-Tunneling 1
+VALUE ASA-IPsec-Split-Tunneling-Policy Local-LAN-Permitted 2
+
+VALUE ASA-IPsec-Tunnel-Type LAN-to-LAN 1
+VALUE ASA-IPsec-Tunnel-Type Remote-Access 2
+
+VALUE ASA-L2TP-MPPC-Compression Disabled 0
+VALUE ASA-L2TP-MPPC-Compression Enabled 1
+
+VALUE ASA-NAC-Enable No 0
+VALUE ASA-NAC-Enable Yes 1
+
+VALUE ASA-Perfect-Forward-Secrecy-Enable No 0
+VALUE ASA-Perfect-Forward-Secrecy-Enable Yes 1
+
+VALUE ASA-PPTP-MPPC-Compression Disabled 0
+VALUE ASA-PPTP-MPPC-Compression Enabled 1
+
+VALUE ASA-Required-Client-Firewall-Vendor-Code Cisco-CIC 1
+VALUE ASA-Required-Client-Firewall-Vendor-Code Zone-Labs 2
+VALUE ASA-Required-Client-Firewall-Vendor-Code NetworkICE 3
+VALUE ASA-Required-Client-Firewall-Vendor-Code Sygate 4
+VALUE ASA-Required-Client-Firewall-Vendor-Code Cisco-IPSA 5
+
+VALUE ASA-Required-Individual-User-Auth Disabled 0
+VALUE ASA-Required-Individual-User-Auth Enabled 1
+
+VALUE ASA-Require-HW-Client-Auth Disabled 0
+VALUE ASA-Require-HW-Client-Auth Enabled 1
+
+VALUE ASA-SessionSubtype None 0
+VALUE ASA-SessionSubtype Clientless 1
+VALUE ASA-SessionSubtype Client 2
+VALUE ASA-SessionSubtype Client-Only 3
+
+VALUE ASA-SessionType None 0
+VALUE ASA-SessionType AnyConnect-Client-SSL-VPN 1
+VALUE ASA-SessionType AnyConnect-Client-IPSec-VPN/IKEv2 2
+VALUE ASA-SessionType Clientless-SSL-VPN 3
+VALUE ASA-SessionType Clientless-Email-Proxy 4
+VALUE ASA-SessionType Cisco-VPN-Client/IKEv1 5
+VALUE ASA-SessionType IKEv1-LAN-to-LAN 6
+VALUE ASA-SessionType IKEv2-LAN-to-LAN 7
+VALUE ASA-SessionType VPN-Load-Balancing 8
+
+VALUE ASA-Smart-Tunnel-Auto Disabled 0
+VALUE ASA-Smart-Tunnel-Auto Enabled 1
+VALUE ASA-Smart-Tunnel-Auto AutoStart 2
+
+VALUE ASA-Strip-Realm Disabled 0
+VALUE ASA-Strip-Realm Enabled 1
+
+VALUE ASA-SVC-Ask Disabled 0
+VALUE ASA-SVC-Ask Enabled 1
+VALUE ASA-SVC-Ask Enable-Default-Service 3
+VALUE ASA-SVC-Ask Enable-Default-Clientless 5
+
+VALUE ASA-SVC-DTLS FALSE 0
+VALUE ASA-SVC-DTLS TRUE 1
+
+VALUE ASA-Use-Client-Address Disabled 0
+VALUE ASA-Use-Client-Address Enabled 1
+
+VALUE ASA-WebVPN-Apply-ACL Disabled 0
+VALUE ASA-WebVPN-Apply-ACL Enabled 1
+
+VALUE ASA-WebVPN-Citrix-Metaframe-Enable Disabled 0
+VALUE ASA-WebVPN-Citrix-Metaframe-Enable Enabled 1
+
+VALUE ASA-WebVPN-File-Access-Enable Disabled 0
+VALUE ASA-WebVPN-File-Access-Enable Enabled 1
+
+VALUE ASA-WebVPN-File-Server-Browsing-Enable Disabled 0
+VALUE ASA-WebVPN-File-Server-Browsing-Enable Enabled 1
+
+VALUE ASA-WebVPN-File-Server-Entry-Enable Disabled 0
+VALUE ASA-WebVPN-File-Server-Entry-Enable Enabled 1
+
+VALUE ASA-WebVPN-Hidden-Shares None 0
+VALUE ASA-WebVPN-Hidden-Shares Visible 1
+
+VALUE ASA-WebVPN-HTTP-Compression Off 0
+VALUE ASA-WebVPN-HTTP-Compression Deflate-Compression 1
+
+VALUE ASA-WebVPN-Port-Forwarding-Enable Disabled 0
+VALUE ASA-WebVPN-Port-Forwarding-Enable Enabled 1
+
+VALUE ASA-WebVPN-Port-Forwarding-Exchange-Proxy-Enable Disabled 0
+VALUE ASA-WebVPN-Port-Forwarding-Exchange-Proxy-Enable Enabled 1
+
+VALUE ASA-WebVPN-Port-Forwarding-HTTP-Proxy Disabled 0
+VALUE ASA-WebVPN-Port-Forwarding-HTTP-Proxy Enabled 1
+
+VALUE ASA-WebVPNSmart-Card-Removal-Disconnect Disabled 0
+VALUE ASA-WebVPNSmart-Card-Removal-Disconnect Enabled 1
+
+VALUE ASA-WebVPN-Smart-Tunnel-Auto-Start Disabled 0
+VALUE ASA-WebVPN-Smart-Tunnel-Auto-Start Enabled 1
+VALUE ASA-WebVPN-Smart-Tunnel-Auto-Start AutoStart 2
+
+VALUE ASA-WebVPN-SSL-VPN-Client-Enable Disabled 0
+VALUE ASA-WebVPN-SSL-VPN-Client-Enable Enabled 1
+
+VALUE ASA-WebVPN-SSL-VPN-Client-Keep-Installation Disabled 0
+VALUE ASA-WebVPN-SSL-VPN-Client-Keep-Installation Enabled 1
+
+VALUE ASA-WebVPN-SSL-VPN-Client-Required Disabled 0
+VALUE ASA-WebVPN-SSL-VPN-Client-Required Enabled 1
+
+VALUE ASA-WebVPN-SVC-DTLS-Enable Disabled 0
+VALUE ASA-WebVPN-SVC-DTLS-Enable Enabled 1
+
+VALUE ASA-WebVPN-SVC-Rekey-Method Off 0
+VALUE ASA-WebVPN-SVC-Rekey-Method SSL 1
+VALUE ASA-WebVPN-SVC-Rekey-Method New-Tunnel 2
+
+VALUE ASA-WebVPN-SVC-Compression Off 0
+VALUE ASA-WebVPN-SVC-Compression Deflate-Compression 1
+
+VALUE ASA-WebVPN-URL-Entry-Enable Disabled 0
+VALUE ASA-WebVPN-URL-Entry-Enable Enabled 1
+
+END-VENDOR Cisco-ASA
ATTRIBUTE CVPN3000-Partition-Mobile-IP-SPI 135 integer
ATTRIBUTE CVPN3000-Strip-Realm 136 integer
ATTRIBUTE CVPN3000-Group-Name 137 integer
-ATTRIBUTE CPVN3000-Smart-Tunnel-Auto 138 integer
-ATTRIBUTE CPVN3000-VLAN 140 integer
-ATTRIBUTE CPVN3000-NAC-Settings 141 string
-ATTRIBUTE CPVN3000-Member-Of 145 string
-ATTRIBUTE CPVN3000-Address-Pools 217 string
-ATTRIBUTE CPVN3000-IPv6-Address-Pools 218 string
-ATTRIBUTE CPVN3000-IPv6-VPN-Filter 219 string
+ATTRIBUTE CVPN3000-Smart-Tunnel-Auto 138 integer
+ATTRIBUTE CVPN3000-VLAN 140 integer
+ATTRIBUTE CVPN3000-NAC-Settings 141 string
+ATTRIBUTE CVPN3000-Member-Of 145 string
+ATTRIBUTE CVPN3000-Address-Pools 217 string
+ATTRIBUTE CVPN3000-IPv6-Address-Pools 218 string
+ATTRIBUTE CVPN3000-IPv6-VPN-Filter 219 string
ATTRIBUTE CVPN3000-Privilege-Level 220 integer
-ATTRIBUTE CPVN3000-WebVPN-Macro-Value1 223 string
-ATTRIBUTE CPVN3000-WebVPN-Macro-Value2 224 string
+ATTRIBUTE CVPN3000-WebVPN-Macro-Value1 223 string
+ATTRIBUTE CVPN3000-WebVPN-Macro-Value2 224 string
VALUE CVPN3000-Allow-Alpha-Only-Passwords Disallow 0
VALUE CVPN3000-Allow-Alpha-Only-Passwords Allow 1
VALUE CVPN3000-Strip-Realm FALSE 0
VALUE CVPN3000-Strip-Realm TRUE 1
-VALUE CPVN3000-Smart-Tunnel-Auto Disabled 0
-VALUE CPVN3000-Smart-Tunnel-Auto Enabled 1
-VALUE CPVN3000-Smart-Tunnel-Auto Auto 2
+VALUE CVPN3000-Smart-Tunnel-Auto Disabled 0
+VALUE CVPN3000-Smart-Tunnel-Auto Enabled 1
+VALUE CVPN3000-Smart-Tunnel-Auto Auto 2
END-VENDOR Cisco-VPN3000
VALUE DHCP-Opcode Client-Message 1
VALUE DHCP-Opcode Server-Message 2
+VALUE DHCP-Message-Type DHCP-Do-Not-Respond 0
VALUE DHCP-Message-Type DHCP-Discover 1
VALUE DHCP-Message-Type DHCP-Offer 2
VALUE DHCP-Message-Type DHCP-Request 3
--- /dev/null
+# -*- text -*-
+# Copyright (C) 2014 The FreeRADIUS Server project and contributors
+#
+# Equallogic Dictionary
+#
+# Equallogic was acquired by Dell in 2008.
+#
+
+VENDOR Equallogic 12740
+
+BEGIN-VENDOR Equallogic
+
+ATTRIBUTE Equallogic-Admin-Full-Name 1 string # Optional
+ATTRIBUTE Equallogic-Admin-Email 2 string # Optional
+ATTRIBUTE Equallogic-Admin-Phone 3 string # Optional
+ATTRIBUTE Equallogic-Admin-Mobile 4 string # Optional
+ATTRIBUTE Equallogic-Poll-Interval 5 integer # Up to 6 numerals, default is 30 (seconds)
+ATTRIBUTE Equallogic-EQL-Admin-Privilege 6 integer
+
+VALUE Equallogic-EQL-Admin-Privilege group-administrator 0
+VALUE Equallogic-EQL-Admin-Privilege pool-administrator 1
+VALUE Equallogic-EQL-Admin-Privilege pool-administrator-ro-entire-group 2
+VALUE Equallogic-EQL-Admin-Privilege volume-administrator 3
+
+# For read-only admin privileges set
+# Equallogic-EQL-Admin-Privilege to 0 and
+# Equallogic-Admin-Account-Type to RO
+
+ATTRIBUTE Equallogic-Admin-Pool-Access 7 string # Comma-separated list of pools
+
+# 'Pool1 25gb' sets the quota for Pool1 to 25GB
+# 'Pool1 500mb' sets a quota of 500MB.
+# 'Pool1 unlimited sets an unlimited quota to pool1
+# If no unit is specified, the default capacity unit is MB.
+
+ATTRIBUTE Equallogic-Admin-Repl-Site-Access 8 string # Comma-separated list of sites
+
+# Required if Equallogic-EQL-Admin-Privilege is 3
+# Used only if Equallogic-EQL-Admin-Privilege is 3
+
+ATTRIBUTE Equallogic-Admin-Account-Type 9 string # RO or RW
+
+END-VENDOR Equallogic
+
--- /dev/null
+#
+# dictionary.ericsson.packet.core.networks
+#
+
+VENDOR Ericsson-Packet-Core-Networks 10923
+
+#
+# Ericsson specific
+
+BEGIN-VENDOR Ericsson-Packet-Core-Networks
+
+ATTRIBUTE Suggested-Rule-Space 30 string
+ATTRIBUTE Suggested-Secondary-Rule-Space 31 string
+
+END-VENDOR Ericsson-Packet-Core-Networks
ATTRIBUTE Packet-Authentication-Vector 1088 octets
ATTRIBUTE Time-Of-Day 1089 string
ATTRIBUTE Request-Processing-Stage 1090 string
+ATTRIBUTE SHA2-Password 1092 octets
ATTRIBUTE SHA-Password 1093 octets
ATTRIBUTE SSHA-Password 1094 octets
ATTRIBUTE SHA1-Password 1093 octets
ATTRIBUTE FreeRADIUS-Client-IP-Address 1120 ipaddr
ATTRIBUTE FreeRADIUS-Client-IPv6-Address 1121 ipv6addr
+# The rest of the FreeRADIUS-Client-* attributes are at 1150...
ATTRIBUTE FreeRADIUS-Client-Require-MA 1122 integer
ATTRIBUTE Cache-Status-Only 1141 integer
ATTRIBUTE Cache-Merge 1142 integer
ATTRIBUTE Cache-Entry-Hits 1143 integer
+ATTRIBUTE Cache-Read-Only 1144 integer
VALUE Cache-Status-Only no 0
VALUE Cache-Status-Only yes 1
VALUE Cache-Merge no 0
VALUE Cache-Merge yes 1
-# More dynamic client attributes
-
-ATTRIBUTE FreeRADIUS-Client-Src-IP-Address 1143 ipaddr
-ATTRIBUTE FreeRADIUS-Client-Src-IPv6-Address 1144 ipv6addr
+VALUE Cache-Read-Only no 0
+VALUE Cache-Read-Only yes 1
ATTRIBUTE OTP-Challenge 1145 string
ATTRIBUTE EAP-Session-Id 1146 octets
ATTRIBUTE Acct-Input-Octets64 1148 integer64
ATTRIBUTE Acct-Output-Octets64 1149 integer64
+ATTRIBUTE FreeRADIUS-Client-IP-Prefix 1150 ipv4prefix
+ATTRIBUTE FreeRADIUS-Client-IPv6-Prefix 1151 ipv6prefix
+ATTRIBUTE FreeRADIUS-Response-Delay 1152 integer
+ATTRIBUTE FreeRADIUS-Client-Src-IP-Address 1153 ipaddr
+ATTRIBUTE FreeRADIUS-Client-Src-IPv6-Address 1154 ipv6addr
+
#
# Range: 1200-1279
# EAP-SIM (and other EAP type) weirdness.
ATTRIBUTE EAP-Sim-KC2 1213 octets
ATTRIBUTE EAP-Sim-KC3 1214 octets
+ATTRIBUTE EAP-Sim-Ki 1215 octets
+ATTRIBUTE EAP-Sim-Algo-Version 1216 integer
+
#
# Range: 1280 - 1535
# EAP-type specific attributes
#
# these are PW_EAP_SIM_X + 1536
+ATTRIBUTE EAP_Sim-Base 1536 octets
ATTRIBUTE EAP-Sim-RAND 1537 octets
ATTRIBUTE EAP-Sim-PADDING 1542 octets
ATTRIBUTE EAP-Sim-NONCE_MT 1543 octets
ATTRIBUTE Tmp-Date-7 1847 date
ATTRIBUTE Tmp-Date-8 1848 date
ATTRIBUTE Tmp-Date-9 1849 date
+
+ATTRIBUTE Tmp-Integer64-0 1871 integer64
+ATTRIBUTE Tmp-Integer64-1 1872 integer64
+ATTRIBUTE Tmp-Integer64-2 1873 integer64
+ATTRIBUTE Tmp-Integer64-3 1874 integer64
+ATTRIBUTE Tmp-Integer64-4 1875 integer64
+ATTRIBUTE Tmp-Integer64-5 1876 integer64
+ATTRIBUTE Tmp-Integer64-6 1877 integer64
+ATTRIBUTE Tmp-Integer64-7 1878 integer64
+ATTRIBUTE Tmp-Integer64-8 1879 integer64
+ATTRIBUTE Tmp-Integer64-9 1880 integer64
#
# These attributes shouldn't be used anywhere. They are defined here
# only for casting of values in conditional expressions.
ATTRIBUTE TLS-Cert-Subject 1913 string
ATTRIBUTE TLS-Cert-Common-Name 1914 string
ATTRIBUTE TLS-Cert-Subject-Alt-Name-Email 1915 string
-# 1916 - 1919: reserved for future cert attributes
+ATTRIBUTE TLS-Cert-Subject-Alt-Name-Dns 1916 string
+ATTRIBUTE TLS-Cert-Subject-Alt-Name-Upn 1917 string
+# 1918 - 1919: reserved for future cert attributes
ATTRIBUTE TLS-Client-Cert-Serial 1920 string
ATTRIBUTE TLS-Client-Cert-Expiration 1921 string
ATTRIBUTE TLS-Client-Cert-Issuer 1922 string
ATTRIBUTE TLS-Client-Cert-X509v3-Subject-Key-Identifier 1928 string
ATTRIBUTE TLS-Client-Cert-X509v3-Authority-Key-Identifier 1929 string
ATTRIBUTE TLS-Client-Cert-X509v3-Basic-Constraints 1930 string
-ATTRIBUTE TLS-PSK-Identity 1931 string
+ATTRIBUTE TLS-Client-Cert-Subject-Alt-Name-Dns 1931 string
+ATTRIBUTE TLS-Client-Cert-Subject-Alt-Name-Upn 1932 string
+ATTRIBUTE TLS-PSK-Identity 1933 string
-# 1932 - 1939: reserved for future cert attributes
+# 1934 - 1939: reserved for future cert attributes
#
# Range: 1940-2099
BEGIN-VENDOR H3C
+ATTRIBUTE H3C-Input-Peak-Rate 1 integer
+ATTRIBUTE H3C-Input-Average-Rate 2 integer
+ATTRIBUTE H3C-Input-Basic-Rate 3 integer
+ATTRIBUTE H3C-Remanent-Volume 15 integer
+ATTRIBUTE H3C-Command 20 integer
+
+VALUE H3C-Command Trigger-Request 1
+VALUE H3C-Command Terminate-Request 2
+VALUE H3C-Command SetPolicy 3
+VALUE H3C-Command Result 4
+VALUE H3C-Command PortalClear 5
+
+ATTRIBUTE H3C-Control-Identifier 24 integer
+ATTRIBUTE H3C-Result-Code 25 integer
ATTRIBUTE H3C-Connect_Id 26 integer
+ATTRIBUTE H3C-Ftp-Directory 28 string
+ATTRIBUTE H3C-Exec-Privilege 29 integer
+
+VALUE H3C-Exec-Privilege Visit 0
+VALUE H3C-Exec-Privilege Monitor 1
+VALUE H3C-Exec-Privilege System 2
+VALUE H3C-Exec-Privilege Manage 33
+
ATTRIBUTE H3C-NAS-Startup-Timestamp 59 integer
ATTRIBUTE H3C-Ip-Host-Addr 60 string
+ATTRIBUTE H3C-User-Notify 61 string
+ATTRIBUTE H3C-User-HeartBeat 62 string
+ATTRIBUTE H3C-User-Group 140 string
+ATTRIBUTE H3C-Security-Level 141 integer
+ATTRIBUTE H3C-Input-Interval-Octets 201 integer
+ATTRIBUTE H3C-Output-Interval-Octets 202 integer
+ATTRIBUTE H3C-Input-Interval-Packets 203 integer
+ATTRIBUTE H3C-Output-Interval-Packets 204 integer
+ATTRIBUTE H3C-Input-Interval-Gigawords 205 integer
+ATTRIBUTE H3C-Output-Interval-Gigawords 206 integer
+ATTRIBUTE H3C-Backup-NAS-IP 207 ipaddr
ATTRIBUTE H3C-Product-ID 255 string
END-VENDOR H3C
# -*- text -*-
-# Copyright (C) 2011 The FreeRADIUS Server project and contributors
+# Copyright (C) 2014 The FreeRADIUS Server project and contributors
##############################################################################
#
# Packeteer VSAs, who followed the Cisco way of putting everything
# into one text string.
#
+# Packeteer was acquired by Blue Coat in 2008.
+#
# $Id$
#
##############################################################################
BEGIN-VENDOR Packeteer
ATTRIBUTE Packeteer-AVPair 1 string
+ATTRIBUTE Packeteer-PC-AVPair 2 string
END-VENDOR Packeteer
# $Id$
#
-ATTRIBUTE EAP-Key-Name 102 string
+ATTRIBUTE EAP-Key-Name 102 octets
#
# $Id$
#
-ATTRIBUTE Chargeable-User-Identity 89 string
+ATTRIBUTE Chargeable-User-Identity 89 octets
# If this attribute exists, it means that IFW has been performed
# for the subscribers session.
#
-ATTRIBUTE IWF-Session 252 octets # 0
+ATTRIBUTE IWF-Session 254 octets # 0
END-VENDOR ADSL-Forum
# http://www.ietf.org/rfc/rfc7055.txt
#
-ATTRIBUTE GSS-Acceptor-Service-Name 164 string
-ATTRIBUTE GSS-Acceptor-Host-Name 165 string
-ATTRIBUTE GSS-Acceptor-Service-Specifics 166 string
-ATTRIBUTE GSS-Acceptor-Realm-Name 167 string
+ATTRIBUTE GSS-Acceptor-Service-Name 164 string
+ATTRIBUTE GSS-Acceptor-Host-Name 165 string
+ATTRIBUTE GSS-Acceptor-Service-Specifics 166 string
+ATTRIBUTE GSS-Acceptor-Realm-Name 167 string
# -*- text -*-
-# Copyright (C) 2011 The FreeRADIUS Server project and contributors
+# Copyright (C) 2014 The FreeRADIUS Server project and contributors
##############################################################################
#
# Symbol VSAs
#
+# Symbol Technologies has been acquired by Motorola in 2007.
+# Some attributes remain in use by products after the acquisition.
+#
# $Id$
#
##############################################################################
BEGIN-VENDOR Symbol
ATTRIBUTE Symbol-Admin-Role 1 integer
+
VALUE Symbol-Admin-Role Monitor 1
VALUE Symbol-Admin-Role Helpdesk 2
VALUE Symbol-Admin-Role NetworkAdmin 4
VALUE Symbol-Admin-Role SysAdmin 8
VALUE Symbol-Admin-Role WebAdmin 16
+VALUE Symbol-Admin-Role Security 32
VALUE Symbol-Admin-Role SuperUser 32768
ATTRIBUTE Symbol-Current-ESSID 2 string
ATTRIBUTE Symbol-Allowed-ESSID 3 string
ATTRIBUTE Symbol-WLAN-Index 4 integer
ATTRIBUTE Symbol-QoS-Profile 5 integer
+
+VALUE Symbol-QoS-Profile BestEffort 1
+VALUE Symbol-QoS-Profile Background 2
+VALUE Symbol-QoS-Profile Video 3
+VALUE Symbol-QoS-Profile Voice 4
+
ATTRIBUTE Symbol-Allowed-Radio 6 string
-ATTRIBUTE Symbol-Expiry-Date-Time 7 string
-ATTRIBUTE Symbol-Start-Date-Time 8 string
+ATTRIBUTE Symbol-Expiry-Date-Time 7 string # Format: MM/DD/YYYY-HH:MM
+ATTRIBUTE Symbol-Start-Date-Time 8 string # Format: MM/DD/YYYY-HH:MM
ATTRIBUTE Symbol-Posture-Status 9 string
-ATTRIBUTE Symbol-Downlink-Limit 10 string
-ATTRIBUTE Symbol-Uplink-Limit 11 string
+ATTRIBUTE Symbol-Downlink-Limit 10 string # Format: 100-10000 (Kbps), 0 = Disabled
+ATTRIBUTE Symbol-Uplink-Limit 11 string # Format: 100-10000 (Kbps), 0 = Disabled
ATTRIBUTE Symbol-User-Group 12 string
ATTRIBUTE Symbol-Login-Source 100 integer
+
VALUE Symbol-Login-Source HTTP 16
VALUE Symbol-Login-Source SSH 32
VALUE Symbol-Login-Source Telnet 64
#
# For TERENA VSA's
#
+# The reference for these values is:
+# http://www.terena.org/activities/tf-emc2/oid.html
+#
# $Id$
#
-VENDOR TERENA 25178
+VENDOR TERENA 25178
-BEGIN-VENDOR TERENA
+BEGIN-VENDOR TERENA
-ATTRIBUTE Eduroam-SP-Country 10 string
+ATTRIBUTE Eduroam-SP-Country 10 string
+ATTRIBUTE Eduroam-Monitoring-Inflate 11 string
-END-VENDOR TERENA
+END-VENDOR TERENA
# About 10 more attributes in 1.3
-
END-VENDOR WiMAX
ATTRIBUTE Xylan-Asa-Access 9 string
ATTRIBUTE Xylan-End-User-Profile 10 integer
ATTRIBUTE Xylan-Access-Priv 16 integer
-ATTRIBUTE Xylan-Nms-Group 20 string
+ATTRIBUTE Xylan-Nms-Group 20 string
ATTRIBUTE Xylan-Nms-First-Name 21 string
ATTRIBUTE Xylan-Nms-Last-Name 22 string
ATTRIBUTE Xylan-Nms-Description 23 string
--- /dev/null
+# -*- text -*-
+# Copyright (C) 2014 The FreeRADIUS Server project and contributors
+#
+# For ZTE.
+#
+# $Id$
+#
+# QoS attributes Mostly derived from:
+# http://wwwen.zte.com.cn/en/products/bearer/201308/P020130828522349526032.pdf
+#
+VENDOR ZTE 3902
+BEGIN-VENDOR ZTE
+
+ATTRIBUTE ZTE-Client-DNS-Pri 1 integer
+ATTRIBUTE ZTE-Client-DNS-Sec 2 integer
+ATTRIBUTE ZTE-Context-Name 4 string
+ATTRIBUTE ZTE-Tunnel-Max-Sessions 21 integer
+ATTRIBUTE ZTE-Tunnel-Max-Tunnels 22 integer
+ATTRIBUTE ZTE-Tunnel-Window 24 integer
+ATTRIBUTE ZTE-Tunnel-Retransmit 25 integer
+ATTRIBUTE ZTE-Tunnel-Cmd-Timeout 26 integer
+ATTRIBUTE ZTE-PPPOE-URL 27 string
+ATTRIBUTE ZTE-PPPOE-MOTM 28 string
+ATTRIBUTE ZTE-Tunnel-Algorithm 31 integer
+ATTRIBUTE ZTE-Tunnel-Deadtime 32 integer
+ATTRIBUTE ZTE-Mcast-Send 33 integer
+ATTRIBUTE ZTE-Mcast-Receive 34 integer
+ATTRIBUTE ZTE-Mcast-MaxGroups 35 integer
+ATTRIBUTE ZTE-Access-Type 74 integer
+
+ATTRIBUTE ZTE-QoS-Type 81 integer
+ATTRIBUTE ZTE-QoS-Profile-Down 82 string
+ATTRIBUTE ZTE-Rate-Ctrl-SCR-Down 83 integer
+ATTRIBUTE ZTE-Rate-Ctrl-Burst-Down 84 integer
+ATTRIBUTE ZTE-Rate-Ctrl-PCR 86 integer
+ATTRIBUTE ZTE-TCP-Syn-Rate 88 integer
+ATTRIBUTE ZTE-Rate-Ctrl-SCR-Up 89 integer
+ATTRIBUTE ZTE-Priority-Level 90 integer
+ATTRIBUTE ZTE-Rate-Ctrl-Burst-Up 91 integer
+ATTRIBUTE ZTE-Rate-Ctrl-Burst-Max-Down 92 integer
+ATTRIBUTE ZTE-Rate-Ctrl-Burst-Max-Up 93 integer
+ATTRIBUTE ZTE-QOS-Profile-Up 94 string
+
+ATTRIBUTE ZTE-TCP-Limit-Num 95 integer
+ATTRIBUTE ZTE-TCP-Limit-Mode 96 integer
+ATTRIBUTE ZTE-IGMP-Service-Profile-Num 97 integer
+ATTRIBUTE ZTE-PPP-Sservice-Type 101 integer
+ATTRIBUTE ZTE-Access-Domain 151 string
+ATTRIBUTE ZTE-VPN-ID 190 string
+
+# 0 (lowest) - 15 (highest) privilege level
+#ATTRIBUTE ZTE-SW-Privilege 191 integer
+
+ATTRIBUTE ZTE_Rate-Bust-DPIR 191 integer
+ATTRIBUTE ZTE_Rate-Bust-UPIR 192 integer
+
+ATTRIBUTE ZTE-Rate-Ctrl-PBS-Down 202 integer
+ATTRIBUTE ZTE-Rate-Ctrl-PBS-Up 203 integer
+ATTRIBUTE ZTE-Rate-Ctrl-SCR-Up-v6 228 integer
+ATTRIBUTE ZTE-Rate-Ctrl-Burst-Up-v6 229 integer
+ATTRIBUTE ZTE-Rate-Ctrl-Burst-Max-Up-v6 230 integer
+ATTRIBUTE ZTE-Rate-Ctrl-PBS-Up-v6 231 integer
+ATTRIBUTE ZTE-QoS-Profile-Up-v6 232 string
+
+ATTRIBUTE ZTE-Rate-Ctrl-SCR-Down-v6 233 integer
+ATTRIBUTE ZTE-Rate-Ctrl-Burst-Down-v6 234 integer
+ATTRIBUTE ZTE-Rate-Ctrl-Burst-Max-Down-v6 235 integer
+ATTRIBUTE ZTE-Rate-Ctrl-PBS-Down-v6 236 integer
+ATTRIBUTE ZTE-QoS-Profile-Down-v6 237 string
+
+END-VENDOR ZTE
autoconf.sed
# Dynamically generated headers
+attributes.h
missing.h
tls.h
features.h
# Version: $Id$
#
-HEADERS = conf.h conffile.h detail.h event.h features.h hash.h heap.h \
- libradius.h md4.h md5.h missing.h modcall.h modules.h \
- packet.h rad_assert.h radius.h radiusd.h radpaths.h \
- radutmp.h realms.h sha1.h stats.h sysutmp.h token.h \
- udpfromto.h base64.h map.h
+HEADERS = \
+ attributes.h \
+ build.h \
+ conf.h \
+ conffile.h \
+ detail.h \
+ event.h \
+ features.h \
+ hash.h \
+ heap.h \
+ libradius.h \
+ md4.h \
+ md5.h \
+ missing.h \
+ modcall.h \
+ modules.h \
+ packet.h \
+ rad_assert.h \
+ radius.h \
+ radiusd.h \
+ radpaths.h \
+ radutmp.h \
+ realms.h \
+ sha1.h \
+ stats.h \
+ sysutmp.h \
+ token.h \
+ udpfromto.h \
+ base64.h \
+ map.h
#
# Build dynamic headers by substituting various values from autoconf.h, these
#
HEADERS_DY = src/include/features.h src/include/missing.h src/include/tls.h \
- src/include/radpaths.h
+ src/include/radpaths.h src/include/attributes.h
src/include/autoconf.sed: src/include/autoconf.h
@grep ^#define $< | sed 's,/\*\*/,1,;' | awk '{print "\
s,defined(" $$2 ")," $$3 ",g;\
s," $$2 ","$$3 ",g;"}' > $@
+src/include/radius.h: | src/include/attributes.h
+
+src/include/attributes.h: share/dictionary.freeradius.internal
+ @$(ECHO) HEADER $@
+ @grep ^ATTRIBUTE $< | awk '{print "PW_"$$2 " " $$3}' | tr 'a-z' 'A-Z' | tr -- - _ | sed 's/^/#define /' > $@
+
src/freeradius-devel/features.h: src/include/features.h src/freeradius-devel
src/include/features.h: src/include/features-h src/include/autoconf.h
/* Define if building universal (internal helper macro) */
#undef AC_APPLE_UNIVERSAL_BUILD
+/* Define if your processor stores words with the most significant byte first
+ */
+#undef BIG_ENDIAN
+
/* BSD-Style get*byaddr_r */
#undef BSDSTYLE
/* Define to 1 if you have the <arpa/inet.h> header file. */
#undef HAVE_ARPA_INET_H
+/* Define if the compiler supports __builtin_choose_expr */
+#undef HAVE_BUILTIN_CHOOSE_EXPR
+
+/* Define if the compiler supports __builtin_types_compatible_p */
+#undef HAVE_BUILTIN_TYPES_COMPATIBLE_P
+
/* Define to 1 if you have the `closefrom' function. */
#undef HAVE_CLOSEFROM
+/* Define to 1 if you have the `collectdclient' library (-lcollectdclient). */
+#undef HAVE_COLLECTDC_H
+
/* Do we have the crypt function */
#undef HAVE_CRYPT
/* Define to 1 if you have the <errno.h> header file. */
#undef HAVE_ERRNO_H
+/* define this if we have <execinfo.h> and symbols */
+#undef HAVE_EXECINFO
+
/* Define to 1 if you have the `fcntl' function. */
#undef HAVE_FCNTL
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
+/* Define to 1 if you have the <features.h> header file. */
+#undef HAVE_FEATURES_H
+
/* Define to 1 if you have the <fnmatch.h> header file. */
#undef HAVE_FNMATCH_H
/* Define to 1 if you have the `ws2_32' library (-lws2_32). */
#undef HAVE_LIBWS2_32
+/* Define to 1 if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
/* Define to 1 if you have the `localtime_r' function. */
#undef HAVE_LOCALTIME_R
/* Define to 1 if you have the <malloc.h> header file. */
#undef HAVE_MALLOC_H
+/* Define to 1 if you have the `mallopt' function. */
+#undef HAVE_MALLOPT
+
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the <openssl/ssl.h> header file. */
#undef HAVE_OPENSSL_SSL_H
-/* Define to 1 if you have the function pcap_dump_fopen. */
+/* Define to 1 if you have the `pcap_activate' function. */
+#undef HAVE_PCAP_ACTIVATE
+
+/* Define to 1 if you have the `pcap_create' function. */
+#undef HAVE_PCAP_CREATE
+
+/* Define to 1 if you have the `pcap_dump_fopen' function. */
#undef HAVE_PCAP_DUMP_FOPEN
-/* Define to 1 if you have the function pcap_fopen_offline. */
+/* Define to 1 if you have the `pcap_fopen_offline' function. */
#undef HAVE_PCAP_FOPEN_OFFLINE
/* Define to 1 if you have the <pcap.h> header file. */
/* Define to 1 if you have the <sys/wait.h> header file. */
#undef HAVE_SYS_WAIT_H
-/* Define if the compiler supports __thread */
-#undef HAVE_THREAD_TLS
+/* Define to 1 if you have the function talloc_set_memlimit. */
+#undef HAVE_TALLOC_SET_MEMLIMIT
+
+/* 128 bit unsigned integer */
+#undef HAVE_UINT128_T
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the <winsock.h> header file. */
#undef HAVE_WINSOCK_H
+/* compiler specific 128 bit unsigned integer */
+#undef HAVE___UINT128_T
+
+/* Define if your processor stores words with the least significant byte first
+ */
+#undef LITTLE_ENDIAN
+
/* define if you have OSFC2 authentication */
#undef OSFC2
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#undef TIME_WITH_SYS_TIME
+/* Define if the compiler supports a thread local storage class */
+#undef TLS_STORAGE_CLASS
+
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
/* Define to `int' if <sys/types.h> does not define. */
#undef pid_t
+/* signal action callback function */
+#undef sig_t
+
/* Define to `unsigned int' if <sys/types.h> does not define. */
#undef size_t
/* uint32_t should be the canonical 'network integer' */
#undef uint32_t
+/* uint64_t is required for larger counters */
+#undef uint64_t
+
/* uint8_t should be the canonical 'octet' for network traffic */
#undef uint8_t
int fr_isbase64(char c);
-size_t fr_base64_encode(uint8_t const *in, size_t inlen, char *out, size_t outlen);
+size_t fr_base64_encode(char *out, size_t outlen, uint8_t const *in, size_t inlen);
-ssize_t fr_base64_decode(char const *in, size_t inlen, uint8_t *out, size_t outlen);
+ssize_t fr_base64_decode(uint8_t *out, size_t outlen, char const *in, size_t inlen);
#endif /* _FR_BASE64_H */
mandir=@mandir@
logdir=@logdir@
raddbdir=@raddbdir@
+dictdir=@dictdir@
radacctdir=@radacctdir@
datarootdir=@datarootdir@
#define RUNDIR "@localstatedir@/run"
#define SBINDIR "@sbindir@"
#define RADIR "@radacctdir@"
+#define DICTDIR "@dictdir@"
EOF
*
* @copyright 2013 The FreeRADIUS server project
*/
+#ifndef _BUILD_H
+#define _BUILD_H
#ifdef __cplusplus
extern "C" {
#endif
+#include <freeradius-devel/autoconf.h> /* Needed for endian macros */
/*
* The ubiquitous stringify macros
*/
#define XSTRINGIFY(x) #x
#define STRINGIFY(x) XSTRINGIFY(x)
+#define JOINSTR(x,y) XSTRINGIFY(x ## y)
/*
- * Macros for controlling warnings in GCC >= 4.2 and clang >= 2.8
+ * HEX concatenation macros
+ */
+#ifndef HEXIFY
+# define XHEXIFY4(b1,b2,b3,b4) (0x ## b1 ## b2 ## b3 ## b4)
+# define HEXIFY4(b1,b2,b3,b4) XHEXIFY4(b1, b2, b3, b4)
+
+# define XHEXIFY3(b1,b2,b3) (0x ## b1 ## b2 ## b3)
+# define HEXIFY3(b1,b2,b3) XHEXIFY3(b1, b2, b3)
+
+# define XHEXIFY2(b1,b2) (0x ## b1 ## b2)
+# define HEXIFY2(b1,b2) XHEXIFY2(b1, b2)
+
+# define XHEXIFY(b1) (0x ## b1)
+# define HEXIFY(b1) XHEXIFY(b1)
+#endif
+
+/*
+ * Only use GCC __attribute__ if were building with a GCClike
+ * compiler.
+ */
+#ifdef __GNUC__
+# define CC_HINT(_x) __attribute__ ((_x))
+#else
+# define CC_HINT(_x)
+#endif
+
+/*
+ * Macros to add pragmas
*/
-#define DIAG_JOINSTR(x,y) XSTRINGIFY(x ## y)
-#define DIAG_DO_PRAGMA(x) _Pragma (#x)
+#define PRAGMA(_x) _Pragma(#_x)
+/*
+ * Macros for controlling warnings in GCC >= 4.2 and clang >= 2.8
+ */
#if defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402
-# define DIAG_PRAGMA(x) DIAG_DO_PRAGMA(GCC diagnostic x)
+# define DIAG_PRAGMA(_x) PRAGMA(GCC diagnostic _x)
# if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406
-# define DIAG_OFF(x) DIAG_PRAGMA(push) DIAG_PRAGMA(ignored DIAG_JOINSTR(-W,x))
-# define DIAG_ON(x) DIAG_PRAGMA(pop)
+# define DIAG_OFF(_x) DIAG_PRAGMA(push) DIAG_PRAGMA(ignored JOINSTR(-W,_x))
+# define DIAG_ON(_x) DIAG_PRAGMA(pop)
# else
-# define DIAG_OFF(x) DIAG_PRAGMA(ignored DIAG_JOINSTR(-W,x))
-# define DIAG_ON(x) DIAG_PRAGMA(warning DIAG_JOINSTR(-W,x))
+# define DIAG_OFF(_x) DIAG_PRAGMA(ignored JOINSTR(-W,_x))
+# define DIAG_ON(_x) DIAG_PRAGMA(warning JOINSTR(-W,_x))
# endif
#elif defined(__clang__) && ((__clang_major__ * 100) + __clang_minor__ >= 208)
-# define DIAG_PRAGMA(x) DIAG_DO_PRAGMA(clang diagnostic x)
-# define DIAG_OFF(x) DIAG_PRAGMA(push) DIAG_PRAGMA(ignored DIAG_JOINSTR(-W,x))
-# define DIAG_ON(x) DIAG_PRAGMA(pop)
+# define DIAG_PRAGMA(_x) PRAGMA(clang diagnostic _x)
+# define DIAG_OFF(_x) DIAG_PRAGMA(push) DIAG_PRAGMA(ignored JOINSTR(-W,_x))
+# define DIAG_ON(_x) DIAG_PRAGMA(pop)
#else
-# define DIAG_OFF(x)
-# define DIAG_ON(x)
+# define DIAG_OFF(_x)
+# define DIAG_ON(_x)
#endif
/*
#if defined(__GNUC__)
/* force inclusion of ident keywords in the face of optimization */
-#define RCSID(id) static char const rcsid[] __attribute__ ((used)) = id;
-#define RCSIDH(h, id) static char const rcsid_ ## h [] __attribute__ ((used)) = id;
+# define RCSID(id) static char const rcsid[] __attribute__ ((used)) = id;
+# define RCSIDH(h, id) static char const rcsid_ ## h [] __attribute__ ((used)) = id;
#elif defined(__SUNPRO_C)
/* put ident keyword into comment section (nicer than gcc way) */
-#define DO_PRAGMA(x) _Pragma(#x)
-#define RCSID(id) DO_PRAGMA(sun ident id)
-#define RCSIDH(h, id) DO_PRAGMA(sun ident id)
+# define RCSID(id) PRAGMA(sun ident id)
+# define RCSIDH(h, id) PRAGMA(sun ident id)
#else
-#define RCSID(id)
-#define RCSIDH(h, id)
+# define RCSID(id)
+# define RCSIDH(h, id)
+#endif
+
+/*
+ * Try and determine endianness of the target system.
+ *
+ * Other projects seem to use endian.h and variants, but these are
+ * in non standard locations, and may mess up cross compiling.
+ *
+ * Here at least the endianess can be set explicitly with
+ * -DLITTLE_ENDIAN or -DBIG_ENDIAN.
+ */
+#if !defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
+# if defined(__LITTLE_ENDIAN__) || \
+ (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
+# define LITTLE_ENDIAN 1
+# elif defined(__BIG_ENDIAN__) || \
+ (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
+# define BIG_ENDIAN 1
+# else
+# error Failed determining endianness of system
+# endif
#endif
#ifdef __cplusplus
}
#endif
+#endif /* _BUILD_H */
#include <stddef.h>
#include <freeradius-devel/token.h>
+#include <sys/time.h>
#ifdef __cplusplus
extern "C" {
typedef struct conf_part CONF_SECTION;
typedef struct conf_data CONF_DATA;
+
+typedef void conf_type_mismatch;
+typedef void conf_type_invalid;
+
+#if defined(HAVE_BUILTIN_CHOOSE_EXPR) && defined(HAVE_BUILTIN_TYPES_COMPATIBLE_P)
+/*
+ * Dumb hack for GCC which explodes with lots of errors masking the real
+ * error cause, if we don't use typdefs for these structures.
+ */
+typedef struct timeval _timeval_t;
+
+/*
+ * Validation macro to check the type of the pointer or offset passed in
+ * matches the type of the configuration item.
+ */
+# define FR_CONF_TYPE_CHECK(_t, _ct, _p) \
+ __builtin_choose_expr((_t == PW_TYPE_STRING),\
+ __builtin_choose_expr(__builtin_types_compatible_p(char const **, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((_t == PW_TYPE_BOOLEAN),\
+ __builtin_choose_expr(__builtin_types_compatible_p(bool *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((_t == PW_TYPE_SUBSECTION),\
+ NULL,\
+ __builtin_choose_expr((_t == PW_TYPE_INTEGER),\
+ __builtin_choose_expr(__builtin_types_compatible_p(uint32_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((_t == PW_TYPE_IPV4_ADDR),\
+ __builtin_choose_expr(__builtin_types_compatible_p(fr_ipaddr_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((_t == PW_TYPE_DATE),\
+ __builtin_choose_expr(__builtin_types_compatible_p(uint32_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((_t == PW_TYPE_ABINARY),\
+ __builtin_choose_expr(__builtin_types_compatible_p(size_t[32/sizeof(size_t)], _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((_t == PW_TYPE_OCTETS),\
+ __builtin_choose_expr(__builtin_types_compatible_p(uint8_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((_t == PW_TYPE_IFID),\
+ __builtin_choose_expr(__builtin_types_compatible_p(uint8_t[8], _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((_t == PW_TYPE_IPV6_ADDR),\
+ __builtin_choose_expr(__builtin_types_compatible_p(fr_ipaddr_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((_t == PW_TYPE_IPV6_PREFIX),\
+ __builtin_choose_expr(__builtin_types_compatible_p(fr_ipaddr_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((_t == PW_TYPE_BYTE),\
+ __builtin_choose_expr(__builtin_types_compatible_p(uint8_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((_t == PW_TYPE_SHORT),\
+ __builtin_choose_expr(__builtin_types_compatible_p(uint16_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((_t == PW_TYPE_ETHERNET),\
+ __builtin_choose_expr(__builtin_types_compatible_p(uint8_t[6], _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((_t == PW_TYPE_SIGNED),\
+ __builtin_choose_expr(__builtin_types_compatible_p(int32_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((_t == PW_TYPE_IP_ADDR),\
+ __builtin_choose_expr(__builtin_types_compatible_p(fr_ipaddr_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((_t == PW_TYPE_INTEGER64),\
+ __builtin_choose_expr(__builtin_types_compatible_p(uint64_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((_t == PW_TYPE_IPV4_PREFIX),\
+ __builtin_choose_expr(__builtin_types_compatible_p(fr_ipaddr_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((_t == PW_TYPE_TIMEVAL),\
+ __builtin_choose_expr(__builtin_types_compatible_p(_timeval_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((_t == PW_TYPE_IP_PREFIX),\
+ __builtin_choose_expr(__builtin_types_compatible_p(fr_ipaddr_t *, _ct), _p, (conf_type_mismatch) 0),\
+ (conf_type_invalid) 0\
+ ))))))))))))))))))))
+
+# define FR_CONF_OFFSET(_t, _s, _f) _t, FR_CONF_TYPE_CHECK(((_t) & 0xff), __typeof__(&(((_s *)NULL)->_f)), offsetof(_s, _f)), NULL
+# define FR_CONF_POINTER(_t, _p) _t, 0, FR_CONF_TYPE_CHECK(((_t) & 0xff), __typeof__(_p), _p)
+# define FR_ITEM_POINTER(_t, _p) _t, FR_CONF_TYPE_CHECK(((_t) & 0xff), __typeof__(_p), _p)
+#else
+# define FR_CONF_OFFSET(_t, _s, _f) _t, offsetof(_s, _f), NULL
+# define FR_CONF_POINTER(_t, _p) _t, 0, _p
+# define FR_ITEM_POINTER(_t, _p) _t, _p
+#endif
+
/*
* Instead of putting the information into a configuration structure,
* the configuration file routines MAY just parse it directly into
* user-supplied variables.
*/
-#define PW_TYPE_STRING_PTR 100
-#define PW_TYPE_BOOLEAN 101
#define PW_TYPE_SUBSECTION 102
-#define PW_TYPE_FILE_INPUT 103
-#define PW_TYPE_FILE_OUTPUT 104
-#define PW_TYPE_DEPRECATED (1 << 10)
-#define PW_TYPE_REQUIRED (1 << 11)
-#define PW_TYPE_ATTRIBUTE (1 << 12)
+
+/*
+ * Configuration type flags, these modify the processing of config
+ * items.
+ */
+#define PW_TYPE_DEPRECATED (1 << 10) //!< CONF_PAIR is deprecated, the server will refuse to start
+ //!< if it finds a CONFIG_ITEM with this flag.
+#define PW_TYPE_REQUIRED (1 << 11) //!< CONF_PAIR is required, server will not start without this
+ //!< config item.
+#define PW_TYPE_ATTRIBUTE (1 << 12) //!< CONF_PAIR value must exist in the dictionary as an attribute.
+#define PW_TYPE_SECRET (1 << 13) //!< don't print it when debug_flag==2.
+
+/*
+ * File i/o types have a base type of string, so they're validate
+ * correctly by the config parser.
+ */
+#define PW_TYPE_FILE_INPUT ((1 << 14) | PW_TYPE_STRING)
+#define PW_TYPE_FILE_OUTPUT ((1 << 15) | PW_TYPE_STRING)
+
+#define FR_INTEGER_COND_CHECK(_name, _var, _cond, _new)\
+do {\
+ if (!(_cond)) {\
+ WARN("WARNING: Ignoring \"" _name " = %i\", forcing to \"" _name " = %i\"", _var, _new);\
+ _var = _new;\
+ }\
+} while (0)
+
+#define FR_INTEGER_BOUND_CHECK(_name, _var, _op, _bound) FR_INTEGER_COND_CHECK(_name, _var, (_var _op _bound), _bound)
+
+#define FR_TIMEVAL_BOUND_CHECK(_name, _var, _op, _bound_sec, _bound_usec)\
+do {\
+ struct timeval _bound = {_bound_sec, _bound_usec};\
+ if (!timercmp(_var, &_bound, _op)) {\
+ WARN("WARNING: Ignoring \"" _name " = %d.%.06d\", forcing to \"" _name " = %d.%06d\"",\
+ (int)(_var)->tv_sec, (int)(_var)->tv_usec,\
+ (int)_bound.tv_sec, (int)_bound.tv_usec);\
+ *_var = _bound;\
+ }\
+} while (0)
typedef struct CONF_PARSER {
- char const *name;
- int type; /* PW_TYPE_STRING, etc. */
- size_t offset; /* relative pointer within "base" */
- void *data; /* absolute pointer if base is NULL */
- const void *dflt; /* default as it would appear in radiusd.conf */
+ char const *name;
+ int type; //!< PW_TYPE_STRING, etc.
+ size_t offset; //!< Relative pointer within "base".
+ void *data; //!< Absolute pointer if base is NULL.
+ const void *dflt; //!< Default as it would appear in radiusd.conf.
} CONF_PARSER;
-CONF_SECTION *cf_section_alloc(CONF_SECTION *parent, char const *name1,
- char const *name2);
-int cf_pair_replace(CONF_SECTION *cs, CONF_PAIR *cp,
- char const *value);
-int cf_item_parse(CONF_SECTION *cs, char const *name,
- int type, void *data, char const *dflt);
-int cf_section_parse(CONF_SECTION *, void *base,
- CONF_PARSER const *variables);
+CONF_SECTION *cf_section_alloc(CONF_SECTION *parent, char const *name1, char const *name2);
+int cf_pair_replace(CONF_SECTION *cs, CONF_PAIR *cp, char const *value);
+int cf_item_parse(CONF_SECTION *cs, char const *name, int type, void *data, char const *dflt);
+int cf_section_parse(CONF_SECTION *, void *base, CONF_PARSER const *variables);
const CONF_PARSER *cf_section_parse_table(CONF_SECTION *cs);
CONF_SECTION *cf_file_read(char const *file);
void cf_file_free(CONF_SECTION *cs);
VALUE_PAIR *cf_pairtovp(CONF_PAIR *pair);
char const *cf_section_name1(CONF_SECTION const *);
char const *cf_section_name2(CONF_SECTION const *);
+FR_TOKEN cf_section_name2_type(CONF_SECTION const *cs);
int dump_config(CONF_SECTION const *cs);
CONF_SECTION *cf_subsection_find_next(CONF_SECTION const *section,
CONF_SECTION const *subsection,
CONF_SECTION *cf_itemtosection(CONF_ITEM const *item);
CONF_ITEM *cf_pairtoitem(CONF_PAIR const *cp);
CONF_ITEM *cf_sectiontoitem(CONF_SECTION const *cs);
-int cf_section_template(CONF_SECTION *cs, CONF_SECTION *template);
-void cf_log_err(CONF_ITEM const *ci, char const *fmt, ...)
-#ifdef __GNUC__
- __attribute__ ((format (printf, 2, 3)))
-#endif
-;
-void cf_log_err_cs(CONF_SECTION const *cs, char const *fmt, ...)
-#ifdef __GNUC__
- __attribute__ ((format (printf, 2, 3)))
-#endif
-;
-void cf_log_err_cp(CONF_PAIR const *cp, char const *fmt, ...)
-#ifdef __GNUC__
- __attribute__ ((format (printf, 2, 3)))
-#endif
-;
-void cf_log_info(CONF_SECTION const *cs, char const *fmt, ...)
-#ifdef __GNUC__
- __attribute__ ((format (printf, 2, 3)))
-#endif
-;
-void cf_log_module(CONF_SECTION const *cs, char const *fmt, ...)
-#ifdef __GNUC__
- __attribute__ ((format (printf, 2, 3)))
-#endif
-;
+void cf_log_err(CONF_ITEM const *ci, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
+void cf_log_err_cs(CONF_SECTION const *cs, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
+void cf_log_err_cp(CONF_PAIR const *cp, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
+void cf_log_info(CONF_SECTION const *cs, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
+void cf_log_module(CONF_SECTION const *cs, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
+
CONF_ITEM *cf_reference_item(CONF_SECTION const *parentcs,
CONF_SECTION *outercs,
char const *ptr);
-extern int cf_pair2xml(FILE *fp, CONF_PAIR const *cp);
-extern int cf_section2xml(FILE *fp, CONF_SECTION const *cs);
-extern int cf_pair2file(FILE *fp, CONF_PAIR const *cp);
-extern int cf_section2file(FILE *fp, CONF_SECTION const *cs);
extern CONF_SECTION *root_config;
-/*
- * Big magic.
- */
-int cf_section_migrate(CONF_SECTION *dst, CONF_SECTION *src);
-
#ifdef __cplusplus
}
#endif
fr_connection_create_t c,
fr_connection_alive_t a,
fr_connection_delete_t d,
- char *prefix);
+ char const *prefix);
void fr_connection_pool_delete(fr_connection_pool_t *pool);
-int fr_connection_check(fr_connection_pool_t *pool, void *conn);
void *fr_connection_get(fr_connection_pool_t *pool);
+int fr_connection_get_num(fr_connection_pool_t *pool);
void fr_connection_release(fr_connection_pool_t *pool, void *conn);
void *fr_connection_reconnect(fr_connection_pool_t *pool, void *conn);
-int fr_connection_add(fr_connection_pool_t *pool, void *conn);
int fr_connection_del(fr_connection_pool_t *pool, void *conn);
#ifdef __cplusplus
STATE_REPLIED
} detail_state_t;
+/*
+ * Allow people to revert to the old behavior if desired.
+ * Also, use the old code if we don't have threads.
+ * FIXME: delete the old (crappy) code, and enable the new
+ * code to work without threads. One thing at a time...
+ */
+#ifndef WITHOUT_DETAIL_THREAD
+#ifdef HAVE_PTHREAD_H
+#define WITH_DETAIL_THREAD (1)
+#endif
+#endif
+
typedef struct listen_detail_t {
fr_event_t *ev; /* has to be first entry (ugh) */
int delay_time;
- char *filename;
- char *filename_work;
+ char const *filename;
+ char const *filename_work;
VALUE_PAIR *vps;
+ int work_fd;
+#ifdef WITH_DETAIL_THREAD
+ int master_pipe[2];
+ int child_pipe[2];
+ pthread_t pthread_id;
+#endif
FILE *fp;
off_t offset;
detail_state_t state;
time_t timestamp;
time_t running;
fr_ipaddr_t client_ip;
- int load_factor; /* 1..100 */
+
+ uint32_t load_factor; /* 1..100 */
+ uint32_t poll_interval;
+ uint32_t retry_interval;
+
int signal;
- int poll_interval;
- int retry_interval;
int packets;
int tries;
bool one_shot;
int fr_dhcp_add_arp_entry(int fd, char const *interface, VALUE_PAIR *hwvp, VALUE_PAIR *clvp);
+int8_t fr_dhcp_attr_cmp(void const *a, void const *b);
+ssize_t fr_dhcp_encode_option(uint8_t *out, size_t outlen, TALLOC_CTX *ctx, vp_cursor_t *cursor);
int fr_dhcp_encode(RADIUS_PACKET *packet);
ssize_t fr_dhcp_decode_options(RADIUS_PACKET *packet,
uint8_t const *data, size_t len, VALUE_PAIR **head);
typedef void (*fr_event_status_t)(struct timeval *);
typedef void (*fr_event_fd_handler_t)(fr_event_list_t *el, int sock, void *ctx);
-fr_event_list_t *fr_event_list_create(fr_event_status_t status);
-void fr_event_list_free(fr_event_list_t *el);
+fr_event_list_t *fr_event_list_create(TALLOC_CTX *ctx, fr_event_status_t status);
+int fr_event_list_num_fds(fr_event_list_t *el);
int fr_event_list_num_elements(fr_event_list_t *el);
int fr_event_insert(fr_event_list_t *el,
fr_event_callback_t callback,
- void *ctx, struct timeval *when, fr_event_t **ev_p);
-int fr_event_delete(fr_event_list_t *el, fr_event_t **ev_p);
+ void *ctx, struct timeval *when, fr_event_t **parent);
+int fr_event_delete(fr_event_list_t *el, fr_event_t **parent);
int fr_event_run(fr_event_list_t *el, struct timeval *when);
int fr_event_fd_delete(fr_event_list_t *el, int type, int fd);
int fr_event_loop(fr_event_list_t *el);
void fr_event_loop_exit(fr_event_list_t *el, int code);
+bool fr_event_loop_exiting(fr_event_list_t *el);
#ifdef __cplusplus
}
* into individual modules.
*/
#ifndef WITHOUT_PROXY
-#define WITH_PROXY (1)
+# define WITH_PROXY (1)
+#else
+# define WITHOUT_COA (1)
#endif
#ifndef WITHOUT_UNLANG
-#define WITH_UNLANG (1)
+# define WITH_UNLANG (1)
#endif
#ifndef WITHOUT_ACCOUNTING
-#define WITH_ACCOUNTING (1)
+# define WITH_ACCOUNTING (1)
#endif
#ifdef WITH_ACCOUNTING
-#ifndef WITHOUT_DETAIL
-#define WITH_DETAIL (1)
-#endif
+# ifndef WITHOUT_DETAIL
+# define WITH_DETAIL (1)
+# endif
#endif
#ifdef WITH_ACCOUNTING
-#ifndef WITHOUT_SESSION_MGMT
-#define WITH_SESSION_MGMT (1)
-#endif
+# ifndef WITHOUT_SESSION_MGMT
+# define WITH_SESSION_MGMT (1)
+# endif
#endif
#ifndef WITHOUT_DYNAMIC_CLIENTS
-#define WITH_DYNAMIC_CLIENTS (1)
+# define WITH_DYNAMIC_CLIENTS (1)
#endif
#ifndef WITHOUT_STATS
-#define WITH_STATS
+# define WITH_STATS
#endif
#ifndef WITHOUT_COMMAND_SOCKET
-#ifdef HAVE_SYS_UN_H
-#define WITH_COMMAND_SOCKET (1)
-#endif
+# ifdef HAVE_SYS_UN_H
+# define WITH_COMMAND_SOCKET (1)
+# endif
#endif
#ifndef WITHOUT_COA
-#define WITH_COA (1)
-#ifndef WITH_PROXY
-#error WITH_COA requires WITH_PROXY
-#endif
+# define WITH_COA (1)
+# ifndef WITH_PROXY
+# error WITH_COA requires WITH_PROXY
+# endif
#endif
#ifdef WITHOUT_TLS
-#ifndef HAVE_OPENSSL_SSL_H
-#error TLS requires OpenSSL
-#endif
+# ifndef HAVE_OPENSSL_SSL_H
+# error TLS requires OpenSSL
+# endif
#else
-#ifdef HAVE_OPENSSL_SSL_H
-#ifndef WITH_TLS
-#ifndef NO_OPENSSL
-#define WITH_TLS (1)
-#endif
-#endif
-#endif
+# ifdef HAVE_OPENSSL_SSL_H
+# ifndef WITH_TLS
+# ifndef NO_OPENSSL
+# define WITH_TLS (1)
+# endif
+# endif
+# endif
#endif
uint32_t fr_hash_update(void const *data, size_t size, uint32_t hash);
uint32_t fr_hash_string(char const *p);
-/*
- * If you need fewer than 32-bits of hash, use this macro to get
- * the number of bits in the hash you need. The upper bits of the
- * hash will be set to zero.
- */
-uint32_t fr_hash_fold(uint32_t hash, int bits);
-
typedef struct fr_hash_table_t fr_hash_table_t;
typedef void (*fr_hash_table_free_t)(void *);
typedef uint32_t (*fr_hash_table_hash_t)(void const *);
* @file libradius.h
* @brief Structures and prototypes for the radius library.
*
- * @copyright 1999-2008 The FreeRADIUS server project
+ * @copyright 1999-2014 The FreeRADIUS server project
*/
RCSIDH(libradius_h, "$Id$")
-#include <freeradius-devel/missing.h>
-
-#include <talloc.h>
+/*
+ * Compiler hinting macros. Included here for 3rd party consumers
+ * of libradius.h.
+ */
+#include <freeradius-devel/build.h>
/*
* Let any external program building against the library know what
*/
#include <freeradius-devel/features.h>
+#ifdef WITHOUT_VERSION_CHECK
+# define RADIUSD_MAGIC_NUMBER ((uint64_t) (0xf4ee4ad3f4ee4ad3))
+# define MAGIC_PREFIX(_x) ((uint8_t) 0x00)
+# define MAGIC_VERSION(_x) ((uint32_t) 0x00000000)
+# define MAGIC_COMMIT(_x) ((uint32_t) 0x00000000)
+#else
+# ifdef RADIUSD_VERSION_COMMIT
+# define RADIUSD_MAGIC_NUMBER ((uint64_t) HEXIFY4(f4, RADIUSD_VERSION, RADIUSD_VERSION_COMMIT, 0))
+# else
+# define RADIUSD_MAGIC_NUMBER ((uint64_t) HEXIFY3(f4, RADIUSD_VERSION, 00000000))
+# endif
+# define MAGIC_PREFIX(_x) ((uint8_t) (_x >> 56))
+# define MAGIC_VERSION(_x) ((uint32_t) ((_x >> 32) & 0x00ffffff))
+# define MAGIC_COMMIT(_x) ((uint32_t) (_x & 0xffffffff))
+#endif
+
+/*
+ * Talloc memory allocation is used in preference to malloc throughout
+ * the libraries and server.
+ */
+#include <talloc.h>
+
+/*
+ * Defines signatures for any missing functions.
+ */
+#include <freeradius-devel/missing.h>
+
+/*
+ * Include system headers.
+ */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>
+#include <signal.h>
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
#include <freeradius-devel/threads.h>
#include <freeradius-devel/radius.h>
#include <freeradius-devel/hash.h>
#ifdef SIZEOF_UNSIGNED_INT
-#if SIZEOF_UNSIGNED_INT != 4
-#error FATAL: sizeof(unsigned int) != 4
-#endif
+# if SIZEOF_UNSIGNED_INT != 4
+# error FATAL: sizeof(unsigned int) != 4
+# endif
#endif
/*
#endif
#if defined(WITH_VERIFY_PTR)
-/*
- * Requires typeof(), which is in most modern C compilers.
- */
+# define FREE_MAGIC (0xF4EEF4EE)
/*
-#define VERIFY_VP(_x) do { (void) talloc_get_type_abort(_x, VALUE_PAIR); \
- if (_x->da) { \
- (void) talloc_get_type_abort(_x->da, DICT_ATTR); \
- } \
- } while (0)
-*/
-#define FREE_MAGIC (0xF4EEF4EE)
-
-#define VERIFY_VP(_x) (void) talloc_get_type_abort(_x, VALUE_PAIR)
-#define VERIFY_PACKET(_x) (void) talloc_get_type_abort(_x, RADIUS_PACKET)
+ * @FIXME
+ * Add if (_x->da) (void) talloc_get_type_abort(_x->da, DICT_ATTR);
+ * to the macro below when dictionaries are talloced.
+ */
+# define VERIFY_VP(_x) fr_verify_vp(_x)
+# define VERIFY_LIST(_x) fr_verify_list(NULL, _x)
+# define VERIFY_PACKET(_x) (void) talloc_get_type_abort(_x, RADIUS_PACKET)
#else
-#define VERIFY_VP(_x)
-#define VERIFY_PACKET(_x)
+/*
+ * Even if were building without WITH_VERIFY_PTR
+ * the pointer must not be NULL when these various macros are used
+ * so we can add some sneaky soft asserts.
+ */
+# define VERIFY_VP(_x) fr_assert(_x)
+# define VERIFY_LIST(_x) fr_assert(_x)
+# define VERIFY_PACKET(_x) fr_assert(_x)
#endif
#define AUTH_VECTOR_LEN 16
#define TAG_VALID(x) ((x) > 0 && (x) < 0x20)
#define TAG_VALID_ZERO(x) ((x) < 0x20)
-#define TAG_ANY -128 /* minimum signed char */
-#define TAG_UNUSED 0
+#define TAG_ANY INT8_MIN
+#define TAG_NONE 0
+/** Check if tags are equal
+ *
+ * @param _s tag were matching on.
+ * @param _a tag belonging to the attribute were checking.
+ */
+#define TAG_EQ(_s, _a) ((_s == _a) || (_s == TAG_ANY) || ((_s == TAG_NONE) && (_a == TAG_ANY)))
+
+#define NUM_ANY INT_MIN
+#define NUM_JOIN (INT_MIN + 1)
+#define NUM_COUNT (INT_MIN + 2)
#define PAD(_x, _y) (_y - ((_x) % _y))
-#if defined(__GNUC__)
-# define PRINTF_LIKE(n) __attribute__ ((format(printf, n, n+1)))
-# define NEVER_RETURNS __attribute__ ((noreturn))
-# define UNUSED __attribute__ ((unused))
-# define BLANK_FORMAT " " /* GCC_LINT whines about empty formats */
-#else
-# define PRINTF_LIKE(n) /* ignore */
-# define NEVER_RETURNS /* ignore */
-# define UNUSED /* ignore */
-# define BLANK_FORMAT ""
-#endif
+#define PRINTF_LIKE(n) CC_HINT(format(printf, n, n+1))
+#define NEVER_RETURNS CC_HINT(noreturn)
+#define UNUSED CC_HINT(unused)
+#define BLANK_FORMAT " " /* GCC_LINT whines about empty formats */
typedef struct attr_flags {
unsigned int is_unknown : 1; //!< Attribute number or vendor is unknown.
/** Union containing all data types supported by the server
*
- * This union contains all data types that can be represented with VALUE_PAIRs. It may also be used in other parts
+ * This union contains all data types that can be represented by VALUE_PAIRs. It may also be used in other parts
* of the server where values of different types need to be stored.
*
* PW_TYPE should be an enumeration of the values in this union.
typedef union value_data {
char const *strvalue; //!< Pointer to UTF-8 string.
uint8_t const *octets; //!< Pointer to binary string.
+ uint32_t integer; //!< 32bit unsigned integer.
struct in_addr ipaddr; //!< IPv4 Address.
- struct in6_addr ipv6addr; //!< IPv6 Address.
uint32_t date; //!< Date (32bit Unix timestamp).
- uint32_t integer; //!< 32bit unsigned integer.
+ size_t filter[32/sizeof(size_t)]; //!< Ascend binary format a packed data
+ //!< structure.
+
+ uint8_t ifid[8]; //!< IPv6 interface ID (should be struct?).
+ struct in6_addr ipv6addr; //!< IPv6 Address.
+ uint8_t ipv6prefix[18]; //!< IPv6 prefix (should be struct?).
+
+ uint8_t byte; //!< 8bit unsigned integer.
+ uint16_t ushort; //!< 16bit unsigned integer.
+
+ uint8_t ether[6]; //!< Ethernet (MAC) address.
+
int32_t sinteger; //!< 32bit signed integer.
uint64_t integer64; //!< 64bit unsigned integer.
- size_t filter[32/sizeof(size_t)]; //!< 64bit signed integer.
- uint8_t ifid[8]; /* struct? */ //!< IPv6 interface ID.
- uint8_t ipv6prefix[18]; /* struct? */ //!< IPv6 prefix.
- uint8_t ipv4prefix[6]; /* struct? */ //!< IPv4 prefix.
- uint8_t ether[6]; //!< Ethernet (MAC) address.
+
+ uint8_t ipv4prefix[6]; //!< IPv4 prefix (should be struct?).
+
uint8_t *tlv; //!< Nested TLV (should go away).
void const *ptr; //!< generic pointer.
} value_data_t;
/** Stores an attribute, a value and various bits of other data
*
- * VALUE_PAIRs are the main data structure used in the server, they specify an attribute, it's children and
- * it's siblings.
+ * VALUE_PAIRs are the main data structure used in the server
*
* They also specify what behaviour should be used when the attribute is merged into a new list/tree.
*/
typedef struct vp_cursor {
VALUE_PAIR **first;
VALUE_PAIR *found; //!< pairfind marker.
- VALUE_PAIR *last; //!< Temporary only used for pairinsert
+ VALUE_PAIR *last; //!< Temporary only used for fr_cursor_insert
VALUE_PAIR *current; //!< The current attribute.
VALUE_PAIR *next; //!< Next attribute to process.
} vp_cursor_t;
FR_TOKEN op; //!< Operator.
} VALUE_PAIR_RAW;
-#define vp_strvalue data.strvalue
-#define vp_octets data.octets
-#define vp_ipv6addr data.ipv6addr
-#define vp_ifid data.ifid
-#define vp_ipv6prefix data.ipv6prefix
-#define vp_ipv4prefix data.ipv4prefix
-#define vp_filter data.filter
-#define vp_ether data.ether
-#define vp_signed data.sinteger
-#define vp_tlv data.tlv
-#define vp_integer64 data.integer64
-#define vp_ipaddr data.ipaddr.s_addr
-#define vp_date data.date
-#define vp_integer data.integer
+#define vp_strvalue data.strvalue
+#define vp_integer data.integer
+#define vp_ipaddr data.ipaddr.s_addr
+#define vp_date data.date
+#define vp_filter data.filter
+#define vp_octets data.octets
+#define vp_ifid data.ifid
+#define vp_ipv6addr data.ipv6addr
+#define vp_ipv6prefix data.ipv6prefix
+#define vp_byte data.byte
+#define vp_short data.ushort
+#define vp_ether data.ether
+#define vp_signed data.sinteger
+#define vp_integer64 data.integer64
+#define vp_ipv4prefix data.ipv4prefix
+#define vp_tlv data.tlv
typedef struct fr_ipaddr_t {
int af; /* address family */
struct in_addr ip4addr;
struct in6_addr ip6addr; /* maybe defined in missing.h */
} ipaddr;
+ uint8_t prefix;
uint32_t scope; /* for IPv6 */
} fr_ipaddr_t;
ssize_t offset;
#ifdef WITH_TCP
size_t partial;
+ int proto;
#endif
} RADIUS_PACKET;
+typedef enum {
+ DECODE_FAIL_NONE = 0,
+ DECODE_FAIL_MIN_LENGTH_PACKET,
+ DECODE_FAIL_MIN_LENGTH_FIELD,
+ DECODE_FAIL_MIN_LENGTH_MISMATCH,
+ DECODE_FAIL_HEADER_OVERFLOW,
+ DECODE_FAIL_UNKNOWN_PACKET_CODE,
+ DECODE_FAIL_INVALID_ATTRIBUTE,
+ DECODE_FAIL_ATTRIBUTE_TOO_SHORT,
+ DECODE_FAIL_ATTRIBUTE_OVERFLOW,
+ DECODE_FAIL_MA_INVALID_LENGTH,
+ DECODE_FAIL_ATTRIBUTE_UNDERFLOW,
+ DECODE_FAIL_TOO_MANY_ATTRIBUTES,
+ DECODE_FAIL_MA_MISSING,
+ DECODE_FAIL_MAX
+} decode_fail_t;
+
+/*
+ * Version check.
+ */
+int fr_check_lib_magic(uint64_t magic);
+
/*
* Printing functions.
*/
int fr_utf8_char(uint8_t const *str);
size_t fr_print_string(char const *in, size_t inlen,
char *out, size_t outlen);
+size_t fr_print_string_len(char const *in, size_t inlen);
+
+#define is_truncated(_ret, _max) ((_ret) >= (_max))
+#define truncate_len(_ret, _max) (((_ret) >= (_max)) ? ((_max) - 1) : _ret)
size_t vp_prints_value(char *out, size_t outlen, VALUE_PAIR const *vp, int8_t quote);
-char *vp_aprinttype(TALLOC_CTX *ctx, PW_TYPE type);
-char *vp_aprint(TALLOC_CTX *ctx, VALUE_PAIR const *vp);
size_t vp_prints_value_json(char *out, size_t outlen, VALUE_PAIR const *vp);
-size_t vp_print_name(char *out, size_t outlen, unsigned int attr, unsigned int vendor);
size_t vp_prints(char *out, size_t outlen, VALUE_PAIR const *vp);
void vp_print(FILE *, VALUE_PAIR const *);
void vp_printlist(FILE *, VALUE_PAIR const *);
+char *vp_aprint_type(TALLOC_CTX *ctx, PW_TYPE type);
+char *vp_aprint_value(TALLOC_CTX *ctx, VALUE_PAIR const *vp);
+char *vp_aprint(TALLOC_CTX *ctx, VALUE_PAIR const *vp);
#define fprint_attr_val vp_print
/*
int dict_str2oid(char const *ptr, unsigned int *pattr,
unsigned int *pvendor, int tlv_depth);
int dict_addvendor(char const *name, unsigned int value);
-int dict_addattr(char const *name, int attr, unsigned int vendor, int type, ATTR_FLAGS flags);
+int dict_addattr(char const *name, int attr, unsigned int vendor, PW_TYPE type, ATTR_FLAGS flags);
int dict_addvalue(char const *namestr, char const *attrstr, int value);
int dict_init(char const *dir, char const *fn);
void dict_free(void);
DICT_ATTR const *dict_attrunknownbyname(char const *attribute, int vp_free);
DICT_ATTR const *dict_attrbyvalue(unsigned int attr, unsigned int vendor);
DICT_ATTR const *dict_attrbyname(char const *attr);
+DICT_ATTR const *dict_attrbytagged_name(char const *name);
DICT_ATTR const *dict_attrbytype(unsigned int attr, unsigned int vendor,
PW_TYPE type);
DICT_ATTR const *dict_attrbyparent(DICT_ATTR const *parent, unsigned int attr,
/* radius.c */
int rad_send(RADIUS_PACKET *, RADIUS_PACKET const *, char const *secret);
-int rad_packet_ok(RADIUS_PACKET *packet, int flags);
+bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason);
RADIUS_PACKET *rad_recv(int fd, int flags);
-ssize_t rad_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, int *src_port,
- int *code);
+ssize_t rad_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, int *code);
void rad_recv_discard(int sockfd);
int rad_verify(RADIUS_PACKET *packet, RADIUS_PACKET *original,
char const *secret);
int rad_digest_cmp(uint8_t const *a, uint8_t const *b, size_t length);
RADIUS_PACKET *rad_alloc(TALLOC_CTX *ctx, int newvector);
RADIUS_PACKET *rad_alloc_reply(TALLOC_CTX *ctx, RADIUS_PACKET *);
+RADIUS_PACKET *rad_copy_packet(TALLOC_CTX *ctx, RADIUS_PACKET const *in);
+
void rad_free(RADIUS_PACKET **);
int rad_pwencode(char *encpw, size_t *len, char const *secret,
uint8_t const *vector);
int rad_chap_encode(RADIUS_PACKET *packet, uint8_t *output,
int id, VALUE_PAIR *password);
-int rad_attr_ok(RADIUS_PACKET const *packet, RADIUS_PACKET const *original,
- DICT_ATTR *da,
- uint8_t const *data, size_t length);
-int rad_tlv_ok(uint8_t const *data, size_t length,
- size_t dv_type, size_t dv_length);
-
-ssize_t rad_attr2vp(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
- char const *secret,
- uint8_t const *data, size_t length,
- VALUE_PAIR **pvp);
-
-ssize_t rad_data2vp(unsigned int attribute, unsigned int vendor,
- uint8_t const *data, size_t length,
- VALUE_PAIR **pvp);
-
-ssize_t rad_vp2data(VALUE_PAIR const *vp, uint8_t *out, size_t outlen);
-
-int rad_vp2extended(RADIUS_PACKET const *packet,
- RADIUS_PACKET const *original,
- char const *secret, VALUE_PAIR const **pvp,
- uint8_t *ptr, size_t room);
-int rad_vp2wimax(RADIUS_PACKET const *packet,
- RADIUS_PACKET const *original,
- char const *secret, VALUE_PAIR const **pvp,
- uint8_t *ptr, size_t room);
-int rad_vp2vsa(RADIUS_PACKET const *packet, RADIUS_PACKET const *original,
- char const *secret, VALUE_PAIR const **pvp, uint8_t *start,
- size_t room);
-int rad_vp2rfc(RADIUS_PACKET const *packet,
- RADIUS_PACKET const *original,
- char const *secret, VALUE_PAIR const **pvp,
- uint8_t *ptr, size_t room);
-
-int rad_vp2attr(RADIUS_PACKET const *packet,
- RADIUS_PACKET const *original, char const *secret,
- VALUE_PAIR const **pvp, uint8_t *ptr, size_t room);
+int rad_attr_ok(RADIUS_PACKET const *packet, RADIUS_PACKET const *original,
+ DICT_ATTR *da, uint8_t const *data, size_t length);
+int rad_tlv_ok(uint8_t const *data, size_t length,
+ size_t dv_type, size_t dv_length);
+
+ssize_t data2vp(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
+ char const *secret,
+ DICT_ATTR const *da, uint8_t const *start,
+ size_t const attrlen, size_t const packetlen,
+ VALUE_PAIR **pvp);
+
+ssize_t rad_attr2vp(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
+ char const *secret,
+ uint8_t const *data, size_t length,
+ VALUE_PAIR **pvp);
+
+ssize_t rad_data2vp(unsigned int attribute, unsigned int vendor,
+ uint8_t const *data, size_t length,
+ VALUE_PAIR **pvp);
+
+ssize_t rad_vp2data(uint8_t const **out, VALUE_PAIR const *vp);
+
+int rad_vp2extended(RADIUS_PACKET const *packet,
+ RADIUS_PACKET const *original,
+ char const *secret, VALUE_PAIR const **pvp,
+ uint8_t *ptr, size_t room);
+int rad_vp2wimax(RADIUS_PACKET const *packet,
+ RADIUS_PACKET const *original,
+ char const *secret, VALUE_PAIR const **pvp,
+ uint8_t *ptr, size_t room);
+
+int rad_vp2vsa(RADIUS_PACKET const *packet, RADIUS_PACKET const *original,
+ char const *secret, VALUE_PAIR const **pvp, uint8_t *start,
+ size_t room);
+
+int rad_vp2rfc(RADIUS_PACKET const *packet,
+ RADIUS_PACKET const *original,
+ char const *secret, VALUE_PAIR const **pvp,
+ uint8_t *ptr, size_t room);
+
+int rad_vp2attr(RADIUS_PACKET const *packet,
+ RADIUS_PACKET const *original, char const *secret,
+ VALUE_PAIR const **pvp, uint8_t *ptr, size_t room);
/* valuepair.c */
VALUE_PAIR *pairalloc(TALLOC_CTX *ctx, DICT_ATTR const *da);
int pair2unknown(VALUE_PAIR *vp);
void pairfree(VALUE_PAIR **);
VALUE_PAIR *pairfind(VALUE_PAIR *, unsigned int attr, unsigned int vendor, int8_t tag);
-
-#define paircursor(_x, _y) paircursorc(_x,(VALUE_PAIR const * const *) _y)
-VALUE_PAIR *paircursorc(vp_cursor_t *cursor, VALUE_PAIR const * const *node);
-VALUE_PAIR *pairfirst(vp_cursor_t *cursor);
-VALUE_PAIR *pairfindnext(vp_cursor_t *cursor, unsigned int attr, unsigned int vendor, int8_t tag);
-VALUE_PAIR *pairnext(vp_cursor_t *cursor);
-VALUE_PAIR *pairlast(vp_cursor_t *cursor);
-VALUE_PAIR *paircurrent(vp_cursor_t *cursor);
-void pairinsert(vp_cursor_t *cursor, VALUE_PAIR *vp);
-VALUE_PAIR *pairremove(vp_cursor_t *cursor);
+VALUE_PAIR *pairfind_da(VALUE_PAIR *, DICT_ATTR const *da, int8_t tag);
+
+#define fr_cursor_init(_x, _y) _fr_cursor_init(_x,(VALUE_PAIR const * const *) _y)
+VALUE_PAIR *_fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR const * const *node);
+void fr_cursor_copy(vp_cursor_t *out, vp_cursor_t *in);
+VALUE_PAIR *fr_cursor_first(vp_cursor_t *cursor);
+VALUE_PAIR *fr_cursor_last(vp_cursor_t *cursor);
+VALUE_PAIR *fr_cursor_next_by_num(vp_cursor_t *cursor, unsigned int attr, unsigned int vendor, int8_t tag);
+
+VALUE_PAIR *fr_cursor_next_by_da(vp_cursor_t *cursor, DICT_ATTR const *da, int8_t tag)
+ CC_HINT(nonnull);
+
+VALUE_PAIR *fr_cursor_next(vp_cursor_t *cursor);
+VALUE_PAIR *fr_cursor_current(vp_cursor_t *cursor);
+void fr_cursor_insert(vp_cursor_t *cursor, VALUE_PAIR *vp);
+VALUE_PAIR *fr_cursor_remove(vp_cursor_t *cursor);
+VALUE_PAIR *fr_cursor_replace(vp_cursor_t *cursor, VALUE_PAIR *new);
void pairdelete(VALUE_PAIR **, unsigned int attr, unsigned int vendor, int8_t tag);
void pairadd(VALUE_PAIR **, VALUE_PAIR *);
void pairreplace(VALUE_PAIR **first, VALUE_PAIR *add);
-int paircmp(VALUE_PAIR *check, VALUE_PAIR *data);
-int paircmp_op(VALUE_PAIR const *one, FR_TOKEN op, VALUE_PAIR const *two);
-void pairsort(VALUE_PAIR **vps, bool with_tag);
-bool pairvalidate(VALUE_PAIR *filter, VALUE_PAIR *list);
+int8_t paircmp_value(VALUE_PAIR const *a, VALUE_PAIR const *b);
+int8_t paircmp_op(VALUE_PAIR const *a, FR_TOKEN op, VALUE_PAIR const *b);
+int8_t paircmp(VALUE_PAIR *a, VALUE_PAIR *b);
+int8_t pairlistcmp(VALUE_PAIR *a, VALUE_PAIR *b);
+
+typedef int8_t (*fr_cmp_t)(void const *a, void const *b);
+int8_t attrcmp(void const *a, void const *b);
+int8_t attrtagcmp(void const *a, void const *b);
+void pairsort(VALUE_PAIR **vps, fr_cmp_t cmp);
+void pairvalidate_debug(TALLOC_CTX *ctx, VALUE_PAIR const *failed[2]);
+bool pairvalidate(VALUE_PAIR const *failed[2], VALUE_PAIR *filter, VALUE_PAIR *list);
+bool pairvalidate_relaxed(VALUE_PAIR const *failed[2], VALUE_PAIR *filter, VALUE_PAIR *list);
VALUE_PAIR *paircopyvp(TALLOC_CTX *ctx, VALUE_PAIR const *vp);
VALUE_PAIR *paircopyvpdata(TALLOC_CTX *ctx, DICT_ATTR const *da, VALUE_PAIR const *vp);
VALUE_PAIR *paircopy(TALLOC_CTX *ctx, VALUE_PAIR *from);
VALUE_PAIR *paircopy2(TALLOC_CTX *ctx, VALUE_PAIR *from, unsigned int attr, unsigned int vendor, int8_t tag);
+VALUE_PAIR *pairsteal(TALLOC_CTX *ctx, VALUE_PAIR *from);
void pairmemcpy(VALUE_PAIR *vp, uint8_t const * src, size_t len);
-void pairmemsteal(VALUE_PAIR *vp, uint8_t *src);
-void pairstrsteal(VALUE_PAIR *vp, char *src);
+void pairmemsteal(VALUE_PAIR *vp, uint8_t const *src);
+void pairstrsteal(VALUE_PAIR *vp, char const *src);
void pairstrcpy(VALUE_PAIR *vp, char const * src);
-void pairsprintf(VALUE_PAIR *vp, char const * fmt, ...)
-#ifdef __GNUC__
- __attribute__ ((format (printf, 2, 3)))
-#endif
-;
+void pairstrncpy(VALUE_PAIR *vp, char const * src, size_t len);
+void pairsprintf(VALUE_PAIR *vp, char const * fmt, ...) CC_HINT(format (printf, 2, 3));
void pairmove(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from);
void pairfilter(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from,
- unsigned int attr, unsigned int vendor, int8_t tag);
-bool pairparsevalue(VALUE_PAIR *vp, char const *value);
+ unsigned int attr, unsigned int vendor, int8_t tag);
+VALUE_PAIR *pairmake_ip(TALLOC_CTX *ctx, char const *value,
+ DICT_ATTR *ipv4, DICT_ATTR *ipv6, DICT_ATTR *ipv4_prefix, DICT_ATTR *ipv6_prefix);
+int pairparsevalue(VALUE_PAIR *vp, char const *value, size_t len);
VALUE_PAIR *pairmake(TALLOC_CTX *ctx, VALUE_PAIR **vps, char const *attribute, char const *value, FR_TOKEN op);
int pairmark_xlat(VALUE_PAIR *vp, char const *value);
FR_TOKEN pairread(char const **ptr, VALUE_PAIR_RAW *raw);
FR_TOKEN userparse(TALLOC_CTX *ctx, char const *buffer, VALUE_PAIR **head);
-VALUE_PAIR *readvp2(TALLOC_CTX *ctx, FILE *fp, int *pfiledone, char const *errprefix);
+int readvp2(VALUE_PAIR **out, TALLOC_CTX *ctx, FILE *fp, bool *pfiledone);
/*
* Error functions.
*/
-#ifdef _LIBRADIUS
-void fr_strerror_printf(char const *, ...)
-#ifdef __GNUC__
- __attribute__ ((format (printf, 1, 2)))
-#endif
-;
-#endif
-void fr_perror(char const *, ...)
-#ifdef __GNUC__
- __attribute__ ((format (printf, 1, 2)))
-#endif
-;
+void fr_strerror_printf(char const *, ...) CC_HINT(format (printf, 1, 2));
+void fr_perror(char const *, ...) CC_HINT(format (printf, 1, 2));
+
extern bool fr_assert_cond(char const *file, int line, char const *expr, bool cond);
#define fr_assert(_x) fr_assert_cond(__FILE__, __LINE__, #_x, (_x))
-extern void _fr_exit(char const *file, int line, int status);
+extern void NEVER_RETURNS _fr_exit(char const *file, int line, int status);
#define fr_exit(_x) _fr_exit(__FILE__, __LINE__, (_x))
-extern void _fr_exit_now(char const *file, int line, int status);
+extern void NEVER_RETURNS _fr_exit_now(char const *file, int line, int status);
#define fr_exit_now(_x) _fr_exit_now(__FILE__, __LINE__, (_x))
extern char const *fr_strerror(void);
+extern char const *fr_syserror(int num);
extern bool fr_dns_lookups; /* do IP -> hostname lookups? */
extern bool fr_hostname_lookups; /* do hostname -> IP lookups? */
extern int fr_debug_flag; /* 0 = no debugging information */
-extern int fr_max_attributes; /* per incoming packet */
+extern uint32_t fr_max_attributes; /* per incoming packet */
#define FR_MAX_PACKET_CODE (52)
extern char const *fr_packet_codes[FR_MAX_PACKET_CODE];
+#define is_radius_code(_x) ((_x > 0) && (_x < FR_MAX_PACKET_CODE))
extern FILE *fr_log_fp;
extern void rad_print_hex(RADIUS_PACKET *packet);
-void fr_printf_log(char const *, ...)
-#ifdef __GNUC__
- __attribute__ ((format (printf, 1, 2)))
-#endif
-;
+void fr_printf_log(char const *, ...) CC_HINT(format (printf, 1, 2));
/*
* Several handy miscellaneous functions.
*/
-void fr_debug_break(void);
+int fr_set_signal(int sig, sig_t func);
+TALLOC_CTX *fr_autofree_ctx(void);
+char const *fr_inet_ntop(int af, void const *src);
char const *ip_ntoa(char *, uint32_t);
+int fr_pton4(fr_ipaddr_t *out, char const *value, size_t inlen, bool resolve, bool fallback);
+int fr_pton6(fr_ipaddr_t *out, char const *value, size_t inlen, bool resolve, bool fallback);
+int fr_pton(fr_ipaddr_t *out, char const *value, size_t inlen, bool resolve);
+bool is_wildcard(fr_ipaddr_t *addr);
+int fr_ntop(char *out, size_t outlen, fr_ipaddr_t *addr);
char *ifid_ntoa(char *buffer, size_t size, uint8_t const *ifid);
uint8_t *ifid_aton(char const *ifid_str, uint8_t *ifid);
int rad_lockfd(int fd, int lock_len);
size_t fr_bin2hex(char *hex, uint8_t const *bin, size_t inlen);
size_t fr_hex2bin(uint8_t *bin, char const *hex, size_t outlen);
uint32_t fr_strtoul(char const *value, char **end);
-bool fr_whitespace_check(char const *value);
+bool is_whitespace(char const *value);
+bool is_integer(char const *value);
+bool is_zero(char const *value);
int fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b);
-int ip_ptonx(char const *src, fr_ipaddr_t *dst);
-int ip_hton(char const *src, int af, fr_ipaddr_t *dst);
+int ip_hton(fr_ipaddr_t *out, int af, char const *hostname, bool fallback);
char const *ip_ntoh(fr_ipaddr_t const *src, char *dst, size_t cnt);
-int fr_ipaddr2sockaddr(fr_ipaddr_t const *ipaddr, int port,
- struct sockaddr_storage *sa, socklen_t *salen);
-int fr_sockaddr2ipaddr(struct sockaddr_storage const *sa, socklen_t salen,
- fr_ipaddr_t *ipaddr, int * port);
+struct in_addr fr_inaddr_mask(struct in_addr const *ipaddr, uint8_t prefix);
+struct in6_addr fr_in6addr_mask(struct in6_addr const *ipaddr, uint8_t prefix);
+void fr_ipaddr_mask(fr_ipaddr_t *addr, uint8_t prefix);
+int fr_ipaddr2sockaddr(fr_ipaddr_t const *ipaddr, uint16_t port,
+ struct sockaddr_storage *sa, socklen_t *salen);
+int fr_sockaddr2ipaddr(struct sockaddr_storage const *sa, socklen_t salen,
+ fr_ipaddr_t *ipaddr, uint16_t *port);
ssize_t fr_utf8_to_ucs2(uint8_t *out, size_t outlen, char const *in, size_t inlen);
+size_t fr_prints_uint128(char *out, size_t outlen, uint128_t const num);
int64_t fr_pow(int32_t base, uint8_t exp);
int fr_get_time(char const *date_str, time_t *date);
-
+int8_t fr_pointer_cmp(void const *a, void const *b);
+void fr_quick_sort(void const *to_sort[], int min_idx, int max_idx, fr_cmp_t cmp);
/*
* Define TALLOC_DEBUG to check overflows with talloc.
* we can't use valgrind, because the memory used by
* talloc is valid memory... just not for us.
*/
#ifdef TALLOC_DEBUG
-void fr_talloc_verify_cb(const void *ptr, int depth,
- int max_depth, int is_ref,
- void *private_data);
+void fr_talloc_verify_cb(const void *ptr, int depth,
+ int max_depth, int is_ref,
+ void *private_data);
#define VERIFY_ALL_TALLOC talloc_report_depth_cb(NULL, 0, -1, fr_talloc_verify_cb, NULL)
#else
#define VERIFY_ALL_TALLOC
#ifdef WITH_ASCEND_BINARY
/* filters.c */
-int ascend_parse_filter(VALUE_PAIR *pair);
-void print_abinary(VALUE_PAIR const *vp, char *buffer, size_t len, int8_t quote);
+int ascend_parse_filter(VALUE_PAIR *vp, char const *value, size_t len);
+void print_abinary(char *out, size_t outlen, VALUE_PAIR const *vp, int8_t quote);
#endif /*WITH_ASCEND_BINARY*/
/* random numbers in isaac.c */
typedef struct fr_randctx {
uint32_t randcnt;
uint32_t randrsl[256];
- uint32_t randmem[256];
+ uint32_t randmem[256];
uint32_t randa;
uint32_t randb;
uint32_t randc;
} fr_randctx;
-void fr_isaac(fr_randctx *ctx);
-void fr_randinit(fr_randctx *ctx, int flag);
-uint32_t fr_rand(void); /* like rand(), but better. */
-void fr_rand_seed(void const *, size_t ); /* seed the random pool */
+void fr_isaac(fr_randctx *ctx);
+void fr_randinit(fr_randctx *ctx, int flag);
+uint32_t fr_rand(void); /* like rand(), but better. */
+void fr_rand_seed(void const *, size_t ); /* seed the random pool */
/* crypt wrapper from crypt.c */
-int fr_crypt_check(char const *key, char const *salt);
+int fr_crypt_check(char const *key, char const *salt);
+
+/* cbuff.c */
+typedef struct fr_cbuff fr_cbuff_t;
+
+fr_cbuff_t *fr_cbuff_alloc(TALLOC_CTX *ctx, uint32_t size, bool lock);
+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 */
+
+/** Optional callback passed to fr_fault_setup
+ *
+ * Allows optional logic to be run before calling the main fault handler.
+ *
+ * If the callback returns < 0, the main fault handler will not be called.
+ *
+ * @param signum signal raised.
+ * @return 0 on success < 0 on failure.
+ */
+typedef int (*fr_fault_cb_t)(int signum);
+typedef struct fr_bt_marker fr_bt_marker_t;
+
+void fr_debug_break(void);
+void backtrace_print(fr_cbuff_t *cbuff, void *obj);
+fr_bt_marker_t *fr_backtrace_attach(fr_cbuff_t **cbuff, TALLOC_CTX *obj);
+
+typedef void (*fr_fault_log_t)(char const *msg, ...) CC_HINT(format (printf, 1, 2));
+
+void fr_panic_on_free(TALLOC_CTX *ctx);
+int fr_set_dumpable_init(void);
+int fr_set_dumpable(bool allow_core_dumps);
+int fr_log_talloc_report(TALLOC_CTX *ctx);
+void fr_fault(int sig);
+int fr_fault_setup(char const *cmd, char const *program);
+void fr_fault_set_cb(fr_fault_cb_t func);
+void fr_fault_set_log_fn(fr_fault_log_t func);
+void fr_fault_set_log_fd(int fd);
+
+#ifdef WITH_VERIFY_PTR
+void fr_verify_vp(VALUE_PAIR const *vp);
+void fr_verify_list(TALLOC_CTX *expected, VALUE_PAIR *vps);
+#endif
/* rbtree.c */
typedef struct rbtree_t rbtree_t;
typedef struct rbnode_t rbnode_t;
+/* callback order for walking */
+typedef enum {
+ RBTREE_PRE_ORDER,
+ RBTREE_IN_ORDER,
+ RBTREE_POST_ORDER,
+ RBTREE_DELETE_ORDER
+} rb_order_t;
+
#define RBTREE_FLAG_NONE (0)
#define RBTREE_FLAG_REPLACE (1 << 0)
#define RBTREE_FLAG_LOCK (1 << 1)
-rbtree_t *rbtree_create(int (*Compare)(void const *, void const *),
- void (*freeNode)(void *),
- int flags);
+
+typedef int (*rb_comparator_t)(void const *ctx, void const *data);
+typedef int (*rb_walker_t)(void *ctx, void *data);
+typedef void (*rb_free_t)(void *data);
+
+rbtree_t *rbtree_create(rb_comparator_t compare, rb_free_t node_free, int flags);
void rbtree_free(rbtree_t *tree);
-bool rbtree_insert(rbtree_t *tree, void *Data);
-rbnode_t *rbtree_insertnode(rbtree_t *tree, void *Data);
-void rbtree_delete(rbtree_t *tree, rbnode_t *Z);
+bool rbtree_insert(rbtree_t *tree, void *data);
+rbnode_t *rbtree_insert_node(rbtree_t *tree, void *data);
+void rbtree_delete(rbtree_t *tree, rbnode_t *z);
bool rbtree_deletebydata(rbtree_t *tree, void const *data);
-rbnode_t *rbtree_find(rbtree_t *tree, void const *Data);
-void *rbtree_finddata(rbtree_t *tree, void const *Data);
-int rbtree_num_elements(rbtree_t *tree);
-void *rbtree_min(rbtree_t *tree);
-void *rbtree_node2data(rbtree_t *tree, rbnode_t *node);
-
-/* callback order for walking */
-typedef enum { PreOrder, InOrder, PostOrder, DeleteOrder } RBTREE_ORDER;
+rbnode_t *rbtree_find(rbtree_t *tree, void const *data);
+void *rbtree_finddata(rbtree_t *tree, void const *data);
+uint32_t rbtree_num_elements(rbtree_t *tree);
+void *rbtree_node2data(rbtree_t *tree, rbnode_t *node);
/*
* The callback should be declared as:
*
* The "context" is some user-defined context.
* The "data" is the pointer to the user data in the node,
- * NOT the node itself.
+ * NOT the node itself.
*
* It should return 0 if all is OK, and !0 for any error.
* The walking will stop on any error.
*
- * Except with DeleteOrder, where the callback should return <0 for
+ * Except with RBTREE_DELETE_ORDER, where the callback should return <0 for
* errors, and may return 1 to delete the current node and halt,
* or 2 to delete the current node and continue. This may be
* used to batch-delete select nodes from a locked rbtree.
*/
-int rbtree_walk(rbtree_t *tree, RBTREE_ORDER order, int (*callback)(void *, void *), void *context);
-
-/*
- * Find a matching data item in an rbtree and, if one is found,
- * perform a callback on it.
- *
- * The callback is similar to rbtree_walk above, except that a
- * positive return code from the callback will cause the found node
- * to be deleted from the tree. If the tree was created with
- * RBTREE_FLAG_LOCK, then the entire find/callback/delete/rebalance
- * sequence happens while the lock is held.
- *
- * Note that the callback MUST NOT alter any of the data which
- * is used as the rbtree key, nor attempt to alter the rest of
- * the rbtree in any way.
- *
- * Returns a pointer to the user data in the found node, or NULL if the
- * item was not found, or NULL if the item was deleted and the tree was
- * created with a freeNode garbage collection routine.
- */
-void *rbtree_callbydata(rbtree_t *tree, void const *Data, int (*callback)(void *, void *), void *context);
+int rbtree_walk(rbtree_t *tree, rb_order_t order, rb_walker_t compare, void *context);
/*
* FIFOs
*/
-typedef struct fr_fifo_t fr_fifo_t;
+typedef struct fr_fifo_t fr_fifo_t;
typedef void (*fr_fifo_free_t)(void *);
-fr_fifo_t *fr_fifo_create(int max_entries, fr_fifo_free_t freeNode);
-void fr_fifo_free(fr_fifo_t *fi);
-int fr_fifo_push(fr_fifo_t *fi, void *data);
-void *fr_fifo_pop(fr_fifo_t *fi);
-void *fr_fifo_peek(fr_fifo_t *fi);
-int fr_fifo_num_elements(fr_fifo_t *fi);
+fr_fifo_t *fr_fifo_create(int max_entries, fr_fifo_free_t freeNode);
+void fr_fifo_free(fr_fifo_t *fi);
+int fr_fifo_push(fr_fifo_t *fi, void *data);
+void *fr_fifo_pop(fr_fifo_t *fi);
+void *fr_fifo_peek(fr_fifo_t *fi);
+int fr_fifo_num_elements(fr_fifo_t *fi);
#ifdef __cplusplus
}
#include <freeradius-devel/packet.h>
#ifdef WITH_TCP
-#include <freeradius-devel/tcp.h>
+# include <freeradius-devel/tcp.h>
#endif
#endif /*LIBRADIUS_H*/
L_DBG = 16, //!< Only displayed when debugging is enabled.
L_DBG_WARN = 17, //!< Warning only displayed when debugging is enabled.
L_DBG_ERR = 18, //!< Error only displayed when debugging is enabled.
- L_DBG_WARN2 = 19, //!< Less severe warning only displayed when debugging is enabled.
- L_DBG_ERR2 = 20 //!< Less severe error only displayed when debugging is enabled.
+ L_DBG_WARN_REQ = 19, //!< Less severe warning only displayed when debugging is enabled.
+ L_DBG_ERR_REQ = 20 //!< Less severe error only displayed when debugging is enabled.
} log_type_t;
typedef enum log_debug {
int colourise; //!< Prefix log messages with VT100 escape codes to change text
//!< colour.
int fd; //!< File descriptor to write messages to.
- log_dst_t dest; //!< Log destination.
- char *file; //!< Path to log file.
- char *debug_file; //!< Path to debug log file.
+ log_dst_t dst; //!< Log destination.
+ char const *file; //!< Path to log file.
+ char const *debug_file; //!< Path to debug log file.
} fr_log_t;
-typedef void (*radlog_func_t)(log_type_t lvl, log_debug_t priority, REQUEST *, char const *, ...);
+typedef void (*radlog_func_t)(log_type_t lvl, log_debug_t priority, REQUEST *, char const *, va_list ap);
extern FR_NAME_NUMBER const syslog_str2fac[];
extern FR_NAME_NUMBER const log_str2dst[];
extern fr_log_t default_log;
-int vradlog(log_type_t lvl, char const *fmt, va_list ap);
-int radlog(log_type_t lvl, char const *fmt, ...)
-#ifdef __GNUC__
- __attribute__ ((format (printf, 2, 3)))
-#endif
-;
-void vp_listdebug(VALUE_PAIR *vp);
-bool radlog_debug_enabled(log_type_t type, log_debug_t lvl, REQUEST *request);
-void radlog_request(log_type_t lvl, log_debug_t priority, REQUEST *request, char const *msg, ...)
-#ifdef __GNUC__
- __attribute__ ((format (printf, 4, 5)))
-#endif
-;
+int radlog_init(fr_log_t *log, bool daemonize);
+
+void vp_listdebug(VALUE_PAIR *vp);
+
+int vradlog(log_type_t lvl, char const *fmt, va_list ap)
+ CC_HINT(format (printf, 2, 0)) CC_HINT(nonnull);
+int radlog(log_type_t lvl, char const *fmt, ...)
+ CC_HINT(format (printf, 2, 3)) CC_HINT(nonnull (2));
+
+bool debug_enabled(log_type_t type, log_debug_t lvl);
+
+bool rate_limit_enabled(void);
+
+bool radlog_debug_enabled(log_type_t type, log_debug_t lvl, REQUEST *request)
+ CC_HINT(nonnull);
-void log_talloc(char const *message);
-void log_talloc_report(TALLOC_CTX *ctx);
+void vradlog_request(log_type_t type, log_debug_t lvl, REQUEST *request, char const *msg, va_list ap)
+ CC_HINT(format (printf, 4, 0)) CC_HINT(nonnull (3, 4));
+
+void radlog_request(log_type_t type, log_debug_t lvl, REQUEST *request, char const *msg, ...)
+ CC_HINT(format (printf, 4, 5)) CC_HINT(nonnull (3, 4));
+
+void radlog_request_error(log_type_t type, log_debug_t lvl, REQUEST *request, char const *msg, ...)
+ CC_HINT(format (printf, 4, 5)) CC_HINT(nonnull (3, 4));
+
+void radlog_request_marker(log_type_t type, log_debug_t lvl, REQUEST *request,
+ char const *fmt, size_t indent, char const *error)
+ CC_HINT(nonnull);
+
+/*
+ * Multiple threads logging to one or more files.
+ */
+typedef struct fr_logfile_t fr_logfile_t;
+
+fr_logfile_t *fr_logfile_init(TALLOC_CTX *ctx);
+int fr_logfile_open(fr_logfile_t *lf, char const *filename, mode_t permissions);
+int fr_logfile_close(fr_logfile_t *lf, int fd);
+int fr_logfile_unlock(fr_logfile_t *lf, int fd);
/*
* Logging macros.
*/
#define _SL(_l, _p, _f, ...) if (debug_flag >= _p) radlog(_l, _f, ## __VA_ARGS__)
-#define DEBUG_ENABLED radlog_debug_enabled(L_DBG, L_DBG_LVL_1, NULL)
-#define DEBUG_ENABLED2 radlog_debug_enabled(L_DBG, L_DBG_LVL_2, NULL)
-#define DEBUG_ENABLED3 radlog_debug_enabled(L_DBG, L_DBG_LVL_3, NULL)
-#define DEBUG_ENABLED4 radlog_debug_enabled(L_DBG, L_DBG_LVL_MAX, NULL)
+#define DEBUG_ENABLED debug_enabled(L_DBG, L_DBG_LVL_1)
+#define DEBUG_ENABLED2 debug_enabled(L_DBG, L_DBG_LVL_2)
+#define DEBUG_ENABLED3 debug_enabled(L_DBG, L_DBG_LVL_3)
+#define DEBUG_ENABLED4 debug_enabled(L_DBG, L_DBG_LVL_MAX)
#define AUTH(fmt, ...) _SL(L_AUTH, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
#define ACCT(fmt, ...) _SL(L_ACCT, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
#define DEBUG4(fmt, ...) _SL(L_DBG, L_DBG_LVL_MAX, fmt, ## __VA_ARGS__)
#define INFO(fmt, ...) _SL(L_INFO, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
-#define DEBUGI(fmt, ...) _SL(L_INFO, L_DBG_LVL_1, fmt, ## __VA_ARGS__)
-
#define WARN(fmt, ...) _SL(L_WARN, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
-#define WDEBUG(fmt, ...) _SL(L_DBG_WARN, L_DBG_LVL_1, fmt, ## __VA_ARGS__)
-#define WDEBUG2(fmt, ...) _SL(L_DBG_WARN, L_DBG_LVL_2, fmt, ## __VA_ARGS__)
-
#define ERROR(fmt, ...) _SL(L_ERR, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
-#define EDEBUG(fmt, ...) _SL(L_DBG_ERR, L_DBG_LVL_1, fmt, ## __VA_ARGS__)
-#define EDEBUG2(fmt, ...) _SL(L_DBG_ERR, L_DBG_LVL_2, fmt, ## __VA_ARGS__)
/*
* Log request driven messages which including elements from the current request, like section and module
*
* If a REQUEST * is available, these functions should be used.
*/
-#define _RL(_l, _p, _f, ...) if (request && request->radlog) request->radlog(_l, _p, request, _f, ## __VA_ARGS__)
-#define _RM(_l, _p, _f, ...) do { \
- if(request) { \
- module_failure_msg(request, _f, ## __VA_ARGS__); \
- _RL(_l, _p, _f, ## __VA_ARGS__); \
- } \
- } while(0)
+#define _RLOG(_l, _p, _f, ...) radlog_request(_l, _p, request, _f, ## __VA_ARGS__)
+#define _RMOD(_l, _p, _f, ...) radlog_request_error(_l, _p, request, _f, ## __VA_ARGS__)
+#define _RMKR(_l, _p, _m, _i, _e) radlog_request_marker(_l, _p, request, _m, _i, _e)
#define RDEBUG_ENABLED radlog_debug_enabled(L_DBG, L_DBG_LVL_1, request)
#define RDEBUG_ENABLED2 radlog_debug_enabled(L_DBG, L_DBG_LVL_2, request)
#define RDEBUG_ENABLED3 radlog_debug_enabled(L_DBG, L_DBG_LVL_3, request)
#define RDEBUG_ENABLED4 radlog_debug_enabled(L_DBG, L_DBG_LVL_MAX, request)
-#define RAUTH(fmt, ...) _RL(L_AUTH, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
-#define RACCT(fmt, ...) _RL(L_ACCT, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
-#define RPROXY(fmt, ...) _RL(L_PROXY, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
+#define RAUTH(fmt, ...) _RLOG(L_AUTH, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
+#define RACCT(fmt, ...) _RLOG(L_ACCT, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
+#define RPROXY(fmt, ...) _RLOG(L_PROXY, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
+
+#define RDEBUGX(_l, fmt, ...) _RLOG(L_DBG, _l, fmt, ## __VA_ARGS__)
+#define RDEBUG(fmt, ...) _RLOG(L_DBG, L_DBG_LVL_1, fmt, ## __VA_ARGS__)
+#define RDEBUG2(fmt, ...) _RLOG(L_DBG, L_DBG_LVL_2, fmt, ## __VA_ARGS__)
+#define RDEBUG3(fmt, ...) _RLOG(L_DBG, L_DBG_LVL_3, fmt, ## __VA_ARGS__)
+#define RDEBUG4(fmt, ...) _RLOG(L_DBG, L_DBG_LVL_MAX, fmt, ## __VA_ARGS__)
+
+#define RINFO(fmt, ...) _RLOG(L_INFO, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
+#define RIDEBUG(fmt, ...) _RLOG(L_INFO, L_DBG_LVL_1, fmt, ## __VA_ARGS__)
+#define RIDEBUG2(fmt, ...) _RLOG(L_INFO, L_DBG_LVL_2, fmt, ## __VA_ARGS__)
+
+#define RWARN(fmt, ...) _RLOG(L_DBG_WARN, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
+#define RWDEBUG(fmt, ...) _RLOG(L_DBG_WARN, L_DBG_LVL_1, fmt, ## __VA_ARGS__)
+#define RWDEBUG2(fmt, ...) _RLOG(L_DBG_WARN, L_DBG_LVL_2, fmt, ## __VA_ARGS__)
-#define RDEBUG(fmt, ...) _RL(L_DBG, L_DBG_LVL_1, fmt, ## __VA_ARGS__)
-#define RDEBUG2(fmt, ...) _RL(L_DBG, L_DBG_LVL_2, fmt, ## __VA_ARGS__)
-#define RDEBUG3(fmt, ...) _RL(L_DBG, L_DBG_LVL_3, fmt, ## __VA_ARGS__)
-#define RDEBUG4(fmt, ...) _RL(L_DBG, L_DBG_LVL_MAX, fmt, ## __VA_ARGS__)
+#define RERROR(fmt, ...) _RMOD(L_DBG_ERR, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
+#define REDEBUG(fmt, ...) _RMOD(L_DBG_ERR, L_DBG_LVL_1, fmt, ## __VA_ARGS__)
+#define REDEBUG2(fmt, ...) _RMOD(L_DBG_ERR, L_DBG_LVL_2, fmt, ## __VA_ARGS__)
+#define REDEBUG3(fmt, ...) _RMOD(L_DBG_ERR, L_DBG_LVL_3, fmt, ## __VA_ARGS__)
+#define REDEBUG4(fmt, ...) _RMOD(L_DBG_ERR, L_DBG_LVL_MAX, fmt, ## __VA_ARGS__)
-#define RINFO(fmt, ...) _RL(L_INFO, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
-#define RIDEBUG(fmt, ...) _RL(L_INFO, L_DBG_LVL_1, fmt, ## __VA_ARGS__)
-#define RIDEBUG2(fmt, ...) _RL(L_INFO, L_DBG_LVL_2, fmt, ## __VA_ARGS__)
+#define RINDENT() (request->log.indent++)
+#define REXDENT() (request->log.indent--)
-#define RWARN(fmt, ...) _RL(L_DBG_WARN, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
-#define RWDEBUG(fmt, ...) _RL(L_DBG_WARN, L_DBG_LVL_1, fmt, ## __VA_ARGS__)
-#define RWDEBUG2(fmt, ...) _RL(L_DBG_WARN, L_DBG_LVL_2, fmt, ## __VA_ARGS__)
+/*
+ * Output string with error marker, showing where format error occurred.
+ *
+ @verbatim
+ my pet kitty
+ ^ kitties are not pets, are nature devouring hell beasts
+ @endverbatim
+ *
+ * @param _m string to mark e.g. "my pet kitty".
+ * @param _i index e.g. 3 (starts from 0).
+ * @param _e error e.g. "kitties are not pets, are nature devouring hell beasts".
+ */
+#define REMARKER(_m, _i, _e) _RMKR(L_DBG_ERR, L_DBG_LVL_1, _m, _i, _e)
+#define RDMARKER(_m, _i, _e) _RMKR(L_DBG, L_DBG_LVL_1, _m, _i, _e)
-#define RERROR(fmt, ...) _RM(L_DBG_ERR, L_DBG_LVL_OFF, fmt, ## __VA_ARGS__)
-#define REDEBUG(fmt, ...) _RM(L_DBG_ERR, L_DBG_LVL_1, fmt, ## __VA_ARGS__)
-#define REDEBUG2(fmt, ...) _RM(L_DBG_ERR, L_DBG_LVL_2, fmt, ## __VA_ARGS__)
-#define REDEBUG3(fmt, ...) _RM(L_DBG_ERR, L_DBG_LVL_3, fmt, ## __VA_ARGS__)
-#define REDEBUG4(fmt, ...) _RM(L_DBG_ERR, L_DBG_LVL_MAX, fmt, ## __VA_ARGS__)
+/*
+ * Rate limit messages.
+ */
+#define RATE_LIMIT_ENABLED rate_limit_enabled()
+#define RATE_LIMIT(_x) \
+do {\
+ if (RATE_LIMIT_ENABLED) {\
+ static time_t _last_complained = 0;\
+ time_t _now = time(NULL);\
+ if (_now != _last_complained) {\
+ _last_complained = _now;\
+ _x;\
+ }\
+ } else _x;\
+} while (0)
#ifdef __cplusplus
}
#include <freeradius-devel/conffile.h>
+#ifdef HAVE_PCREPOSIX_H
+# include <pcreposix.h>
+#else
+# ifdef HAVE_REGEX_H
+# include <regex.h>
+
+/*
+ * For POSIX Regular expressions.
+ * (0) Means no extended regular expressions.
+ * REG_EXTENDED means use extended regular expressions.
+ */
+# ifndef REG_EXTENDED
+# define REG_EXTENDED (0)
+# endif
+
+# ifndef REG_NOSUB
+# define REG_NOSUB (0)
+# endif
+# endif
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
VPT_TYPE_LIST, //!< Is a list.
VPT_TYPE_REGEX, //!< Is a regex.
VPT_TYPE_EXEC, //!< Needs to be executed.
- VPT_TYPE_DATA //!< is a value_data_t
+ VPT_TYPE_DATA, //!< is a value_data_t
+ VPT_TYPE_XLAT_STRUCT, //!< pre-parsed xlat_exp_t
+ VPT_TYPE_REGEX_STRUCT, //!< pre-parsed regex_t
+ VPT_TYPE_NULL //!< VPT has no value
} vpt_type_t;
extern const FR_NAME_NUMBER vpt_types[];
+typedef struct xlat_exp xlat_exp_t;
+
/** A pre-parsed template attribute
*
- * Value pair template, used when processing various mappings sections
- * to create a real valuepair later.
+ * Is used as both the RHS and LHS of a map (both update, and conditional types)
+ *
+ * When used on the LHS it describes an attribute to create and should be one of these types:
+ * - VPT_TYPE_ATTR
+ * - VPT_TYPE_LIST
+ *
+ * When used on the RHS it describes the value to assign to the attribute being created and
+ * should be one of these types:
+ * - VPT_TYPE_LITERAL
+ * - VPT_TYPE_XLAT
+ * - VPT_TYPE_ATTR
+ * - VPT_TYPE_LIST
+ * - VPT_TYPE_EXEC
+ * - VPT_TYPE_DATA
+ * - VPT_TYPE_XLAT_STRUCT (pre-parsed xlat)
+ *
+ * When used as part of a condition it may be any of the RHS side types, as well as:
+ * - VPT_TYPE_REGEX_STRUCT (pre-parsed regex)
*
* @see value_pair_map_t
*/
//!< attribute, just the string id for
//!< the attribute.
- request_refs_t request; //!< Request to search or insert in.
- pair_lists_t list; //!< List to search or insert in.
-
- DICT_ATTR const *da; //!< Resolved dictionary attribute.
- value_data_t const *vpd; //!< actual data
- size_t length; //!< of the vpd data
+ /*
+ * @todo This should be moved into the union, but some code currently
+ * uses value_pair_tmpl_t's to describe both the value and the attribute.
+ * This is wrong, and the code that does this should be converted to use
+ * maps.
+ */
+ struct {
+ request_refs_t request; //!< Request to search or insert in.
+ pair_lists_t list; //!< List to search or insert in.
+
+ DICT_ATTR const *da; //!< Resolved dictionary attribute.
+ int num; //!< for array references
+ int8_t tag; //!< for tag references
+ } attribute;
+
+ union {
+ struct {
+ value_data_t const *value; //!< actual data
+ size_t length; //!< of the vpd data
+ } literal;
+ xlat_exp_t *xlat; //!< pre-parsed xlat_exp_t
+ struct {
+ regex_t *comp; //!< pre-parsed regex_t
+ bool iflag; //!< Case insensitive
+ } preg;
+ } data;
} value_pair_tmpl_t;
+#define vpt_request attribute.request
+#define vpt_list attribute.list
+#define vpt_da attribute.da
+#define vpt_num attribute.num
+#define vpt_tag attribute.tag
+
+#define vpt_xlat data.xlat
+
+#define vpt_preg data.preg.comp
+#define vpt_iflag data.preg.iflag
+
+#define vpt_value data.literal.value
+#define vpt_length data.literal.length
+
/** Value pair map
*
* Value pair maps contain a pair of templates, that describe a src attribute
} value_pair_map_t;
void radius_tmplfree(value_pair_tmpl_t **tmpl);
-int radius_parse_attr(char const *name, value_pair_tmpl_t *vpt,
+int radius_parse_attr(value_pair_tmpl_t *vpt, char const *name,
request_refs_t request_def,
pair_lists_t list_def);
value_pair_tmpl_t *radius_attr2tmpl(TALLOC_CTX *ctx, char const *name,
request_refs_t request_def,
pair_lists_t list_def);
-value_pair_tmpl_t *radius_str2tmpl(TALLOC_CTX *ctx, char const *name, FR_TOKEN type);
+value_pair_tmpl_t *radius_str2tmpl(TALLOC_CTX *ctx, char const *name, FR_TOKEN type,
+ request_refs_t request_def,
+ pair_lists_t list_def);
+bool radius_cast_tmpl(value_pair_tmpl_t *vpt, DICT_ATTR const *da);
size_t radius_tmpl2str(char *buffer, size_t bufsize, value_pair_tmpl_t const *vpt);
int radius_attrmap(CONF_SECTION *cs, value_pair_map_t **head,
pair_lists_t dst_list_def, pair_lists_t src_list_def,
#include <string.h>
-#ifdef WITH_OPENSSL_MD4
+#ifdef HAVE_OPENSSL_MD4_H
#include <openssl/md4.h>
#endif
void fr_md4_calc (unsigned char *, unsigned char const *, unsigned int);
-#ifndef WITH_OPENSSL_MD4
+#ifndef HAVE_OPENSSL_MD4_H
/* The below was retrieved from
* http://www.openbsd.org/cgi-bin/cvsweb/src/include/md4.h?rev=1.12
* With the following changes: uint64_t => uint32_t[2]
/* __attribute__((__bounded__(__minbytes__,1,4)))
__attribute__((__bounded__(__minbytes__,2,MD4_BLOCK_LENGTH)))*/;
/*__END_DECLS*/
-#else /* WITH_OPENSSL_MD4 */
+#else /* HAVE_OPENSSL_MD4_H */
USES_APPLE_DEPRECATED_API
#define FR_MD4_CTX MD4_CTX
#define fr_MD4Init MD4_Init
#include <string.h>
-#ifdef WITH_OPENSSL_MD5
+#ifdef HAVE_OPENSSL_MD5_H
#include <openssl/md5.h>
#endif
extern "C" {
#endif
-#ifndef WITH_OPENSSL_MD5
+#ifndef HAVE_OPENSSL_MD5_H
/* The below was retrieved from
* http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/crypto/md5.h?rev=1.1
* With the following changes: uint64_t => uint32_t[2]
/* __attribute__((__bounded__(__minbytes__,2,MD5_BLOCK_LENGTH)))*/;
/* __END_DECLS */
-#else /* WITH_OPENSSL_HASH */
+#else /* HAVE_OPENSSL_MD5_H */
USES_APPLE_DEPRECATED_API
#define FR_MD5_CTX MD5_CTX
void timeval2ntp(struct timeval const *tv, uint8_t *ntp);
void ntp2timeval(struct timeval *tv, char const *ntp);
-#define ntohll(x) (((uint64_t)(ntohl((uint32_t)((x << 32) >> 32))) << 32) | \
- (uint64_t)ntohl(((uint32_t)(x >> 32))))
+/*
+ * This is really hacky. Any code needing to perform operations on 128bit integers,
+ * or return 128BIT integers should check for HAVE_128BIT_INTEGERS.
+ */
+#ifndef HAVE_UINT128_T
+# ifdef HAVE___UINT128_T
+# define HAVE_128BIT_INTEGERS
+# define uint128_t __uint128_t
+# define int128_t __int128_t
+# else
+typedef struct uint128_t { uint8_t v[16]; } uint128_t;
+typedef struct int128_t { uint8_t v[16]; } int128_t;
+# endif
+#else
+# define HAVE_128BIT_INTEGERS
+#endif
+
+/* abcd efgh -> dcba hgfe -> hgfe dcba */
+#ifdef LITTLE_ENDIAN
+# define ntohll(x) (((uint64_t)ntohl((uint32_t)(x >> 32))) | (((uint64_t)ntohl(((uint32_t) x)) << 32)))
+
+# ifdef HAVE_128BIT_INTEGERS
+# define ntohlll(x) (((uint128_t)ntohll((uint64_t)(x >> 64))) | (((uint128_t)ntohll(((uint64_t) x)) << 64)))
+# else
+uint128_t ntohlll(uint128_t num);
+# endif
+#else
+# define ntohll(x) (x)
+# define ntohlll(x) (x)
+#endif
#define htonll(x) ntohll(x)
+#define htonlll(x) htohlll(x)
#ifdef __cplusplus
}
#endif
+
+char *talloc_typed_strdup(const void *t, const char *p);
+char *talloc_typed_asprintf(const void *t, const char *fmt, ...) CC_HINT(format (printf, 2, 3));
#endif /* _FR_MISSING_H */
/* Create a single modcallable node that references a module instance. This
* may be a CONF_SECTION containing action specifiers like "notfound = return"
* or a simple CONF_PAIR, in which case the default actions are used. */
-modcallable *compile_modsingle(modcallable *parent, rlm_components_t component, CONF_ITEM *ci,
+modcallable *compile_modsingle(modcallable **parent, rlm_components_t component, CONF_ITEM *ci,
char const **modname);
/*
*/
bool modcall_pass2(modcallable *mc);
-/* Add an entry to the end of a modgroup, creating it first if necessary */
-void add_to_modcallable(modcallable **parent, modcallable *this,
- rlm_components_t component, char const *name);
+/* Add an entry to the end of a modgroup */
+void add_to_modcallable(modcallable *parent, modcallable *this);
/* Free a tree returned by compile_modgroup or compile_modsingle */
void modcallable_free(modcallable **pc);
+void modcall_debug(modcallable *mc, int depth);
+
#ifdef __cplusplus
}
#endif
pthread_mutex_t *mutex;
#endif
CONF_SECTION *cs;
- int dead;
+ bool force;
+ rlm_rcode_t code;
fr_module_hup_t *mh;
} module_instance_t;
RCSIDH(modules_h, "$Id$")
#include <freeradius-devel/conffile.h>
+#include <freeradius-devel/features.h>
#ifdef __cplusplus
extern "C" {
#endif
-/** Return codes indicating the result of the module call
- *
- * All module functions must return one of the codes listed below (apart from
- * RLM_MODULE_NUMCODES, which is used to check for validity).
- */
-typedef enum rlm_rcodes {
- RLM_MODULE_REJECT = 0, //!< Immediately reject the request.
- RLM_MODULE_FAIL, //!< Module failed, don't reply.
- RLM_MODULE_OK, //!< The module is OK, continue.
- RLM_MODULE_HANDLED, //!< The module handled the request, so stop.
- RLM_MODULE_INVALID, //!< The module considers the request invalid.
- RLM_MODULE_USERLOCK, //!< Reject the request (user is locked out).
- RLM_MODULE_NOTFOUND, //!< User not found.
- RLM_MODULE_NOOP, //!< Module succeeded without doing anything.
- RLM_MODULE_UPDATED, //!< OK (pairs modified).
- RLM_MODULE_NUMCODES, //!< How many valid return codes there are.
- RLM_MODULE_UNKNOWN //!< Error resolving rcode (should not be
- //!< returned by modules).
-} rlm_rcode_t;
-
/** The different section components of the server
*
* Used as indexes in the methods array in the module_t struct.
#define RLM_TYPE_THREAD_UNSAFE (1 << 0) //!< Module is not threadsafe.
//!< Server will protect calls
//!< with mutex.
-#define RLM_TYPE_CHECK_CONFIG_SAFE (1 << 1) //!< Instantiate module on -C.
- //!< Module will be
+#define RLM_TYPE_CHECK_CONFIG_UNSAFE (1 << 1) //!< Don't instantiate module on -C.
+ //!< Module will NOT be
//!< instantiated if the server
//!< is started in config
//!< check mode.
//!< new instance, and then
//!< destroy old instance.
-#define RLM_MODULE_MAGIC_NUMBER ((uint32_t) (0xf4ee4ad3))
-#define RLM_MODULE_INIT RLM_MODULE_MAGIC_NUMBER
+
+/* Stop people using different module/library/server versions together */
+#define RLM_MODULE_INIT RADIUSD_MAGIC_NUMBER
/** Module section callback
*
* within the module to different sections.
*/
typedef struct module_t {
- uint32_t magic; //!< Used to validate module struct.
+ uint64_t magic; //!< Used to validate module struct.
char const *name; //!< The name of the module (without rlm_ prefix).
int type; //!< One or more of the RLM_TYPE_* constants.
size_t inst_size; //!< Size of the instance data
} module_t;
-int setup_modules(int, CONF_SECTION *);
-int detach_modules(void);
-int module_hup(CONF_SECTION *modules);
+int modules_init(CONF_SECTION *);
+int modules_free(void);
+int modules_hup(CONF_SECTION *modules);
rlm_rcode_t process_authorize(int type, REQUEST *request);
rlm_rcode_t process_authenticate(int type, REQUEST *request);
rlm_rcode_t module_preacct(REQUEST *request);
int fr_inaddr_any(fr_ipaddr_t *ipaddr);
void fr_request_from_reply(RADIUS_PACKET *request,
RADIUS_PACKET const *reply);
-int fr_socket(fr_ipaddr_t *ipaddr, int port);
+int fr_socket(fr_ipaddr_t *ipaddr, uint16_t port);
int fr_nonblock(int fd);
typedef struct fr_packet_list_t fr_packet_list_t;
RADIUS_PACKET *reply);
bool fr_packet_list_yank(fr_packet_list_t *pl,
RADIUS_PACKET *request);
-int fr_packet_list_num_elements(fr_packet_list_t *pl);
+uint32_t fr_packet_list_num_elements(fr_packet_list_t *pl);
bool fr_packet_list_id_alloc(fr_packet_list_t *pl, int proto,
RADIUS_PACKET **request_p, void **pctx);
bool fr_packet_list_id_free(fr_packet_list_t *pl,
RADIUS_PACKET *request, bool yank);
bool fr_packet_list_socket_add(fr_packet_list_t *pl, int sockfd, int proto,
- fr_ipaddr_t *dst_ipaddr, int dst_port,
+ fr_ipaddr_t *dst_ipaddr, uint16_t dst_port,
void *ctx);
bool fr_packet_list_socket_del(fr_packet_list_t *pl, int sockfd);
bool fr_packet_list_socket_freeze(fr_packet_list_t *pl, int sockfd);
bool fr_packet_list_socket_thaw(fr_packet_list_t *pl, int sockfd);
-int fr_packet_list_walk(fr_packet_list_t *pl, void *ctx,
- fr_hash_table_walk_t callback);
+int fr_packet_list_walk(fr_packet_list_t *pl, void *ctx, rb_walker_t callback);
int fr_packet_list_fd_set(fr_packet_list_t *pl, fd_set *set);
RADIUS_PACKET *fr_packet_list_recv(fr_packet_list_t *pl, fd_set *set);
-int fr_packet_list_num_incoming(fr_packet_list_t *pl);
-int fr_packet_list_num_outgoing(fr_packet_list_t *pl);
+uint32_t fr_packet_list_num_incoming(fr_packet_list_t *pl);
+uint32_t fr_packet_list_num_outgoing(fr_packet_list_t *pl);
/*
* "find" returns a pointer to the RADIUS_PACKET* member in the
struct fr_cond_t {
fr_cond_type_t type;
+ CONF_ITEM const *ci;
union {
value_pair_map_t *map;
value_pair_tmpl_t *vpt;
fr_cond_t *child;
} data;
- int regex_i;
int negate;
int pass2_fixup;
/*
* In xlat.c for now
*/
-typedef struct xlat_exp xlat_exp_t;
ssize_t xlat_tokenize(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
char const **error);
size_t xlat_sprint(char *buffer, size_t bufsize, xlat_exp_t const *node);
--- /dev/null
+#ifndef FR_PCAP_H
+#define FR_PCAP_H
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 if the
+ * License as published by the Free Software Foundation.
+ *
+ * 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
+ */
+
+/**
+ * $Id$
+ * @file include/pcap.h
+ * @brief Prototypes and constants for PCAP functions.
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+#include <freeradius-devel/libradius.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <pcap.h>
+
+/*
+ * Length of a DEC/Intel/Xerox or 802.3 Ethernet header.
+ * Note that some compilers may pad "struct ether_header" to
+ * a multiple of 4 *bytes, for example, so "sizeof (struct
+ * ether_header)" may not give the right answer.
+ *
+ * 6 Byte SRC, 6 Byte DST, 2 Byte Ether type, 4 Byte CVID, 4 Byte SVID
+ */
+#define ETHER_HDRLEN 22
+#define IP_HDRLEN 60
+
+/*
+ * RADIUS packet length.
+ * RFC 2865, Section 3., subsection 'length' says:
+ * " ... and maximum length is 4096."
+ */
+#define MAX_RADIUS_LEN 4096
+#define MIN_RADIUS_LEN 20
+#define SNAPLEN ETHER_HDRLEN + IP_HDRLEN + sizeof(struct udp_header) + MAX_RADIUS_LEN
+#define PCAP_BUFFER_DEFAULT (10000)
+/*
+ * It's unclear why this differs between platforms
+ */
+#ifndef __linux__
+# define PCAP_NONBLOCK_TIMEOUT (0)
+#else
+# define PCAP_NONBLOCK_TIMEOUT (-1)
+#endif
+
+#ifndef BIOCIMMEDIATE
+#define BIOCIMMEDIATE (2147762800)
+#endif
+
+/*
+ * Older versions of libpcap don't define this
+ */
+#ifndef PCAP_NETMASK_UNKNOWN
+# define PCAP_NETMASK_UNKNOWN 0
+#endif
+
+/*
+ * The number of bytes in an ethernet (MAC) address.
+ */
+#define ETHER_ADDR_LEN 6
+
+/*
+ * Structure of a DEC/Intel/Xerox or 802.3 Ethernet header.
+ */
+struct ethernet_header {
+ uint8_t ether_dst[ETHER_ADDR_LEN];
+ uint8_t ether_src[ETHER_ADDR_LEN];
+ uint16_t ether_type;
+};
+
+/*
+ * Structure of an internet header, naked of options.
+ */
+
+#define IP_V(ip) (((ip)->ip_vhl & 0xf0) >> 4)
+#define IP_HL(ip) ((ip)->ip_vhl & 0x0f)
+
+#define I_DF 0x4000 //!< Dont fragment flag.
+#define IP_MF 0x2000 //!< More fragments flag.
+#define IP_OFFMASK 0x1fff //!< Mask for fragmenting bits.
+
+typedef struct ip_header {
+ uint8_t ip_vhl; //!< Header length, version.
+
+ uint8_t ip_tos; //!< Type of service.
+ uint16_t ip_len; //!< Total length.
+ uint16_t ip_id; //!< identification.
+ uint16_t ip_off; //!< Fragment offset field.
+
+ uint8_t ip_ttl; //!< Time To Live.
+ uint8_t ip_p; //!< Protocol.
+ uint16_t ip_sum; //!< Checksum.
+ struct in_addr ip_src, ip_dst; //!< Src and Dst address
+} ip_header_t;
+
+typedef struct ip_header6 {
+ uint32_t ip_vtcfl; //!< Version, traffic class, flow label.
+ uint16_t ip_len; //!< Payload length
+
+ uint8_t ip_next; //!< Next header (protocol)
+ uint8_t ip_hopl; //!< IP Hop Limit
+
+ struct in6_addr ip_src, ip_dst; //!< Src and Dst address
+} ip_header6_t;
+
+/*
+ * UDP protocol header.
+ * Per RFC 768, September, 1981.
+ */
+typedef struct udp_header {
+ uint16_t src; //!< Source port.
+ uint16_t dst; //!< Destination port.
+ uint16_t len; //!< UDP length.
+ uint16_t checksum; //!< UDP checksum.
+} udp_header_t;
+
+typedef struct radius_packet_t {
+ uint8_t code;
+ uint8_t id;
+ uint8_t length[2];
+ uint8_t vector[AUTH_VECTOR_LEN];
+ uint8_t data[1];
+} radius_packet_t;
+
+#define AUTH_HDR_LEN 20
+
+typedef enum {
+ PCAP_INVALID = 0,
+ PCAP_INTERFACE_IN,
+ PCAP_FILE_IN,
+ PCAP_STDIO_IN,
+ PCAP_INTERFACE_OUT,
+ PCAP_FILE_OUT,
+ PCAP_STDIO_OUT
+} fr_pcap_type_t;
+
+extern const FR_NAME_NUMBER pcap_types[];
+
+/*
+ * Internal pcap structures
+ */
+typedef struct fr_pcap fr_pcap_t;
+struct fr_pcap {
+ char errbuf[PCAP_ERRBUF_SIZE]; //!< Last error on this interface.
+ fr_pcap_type_t type; //!< What type of handle this is.
+ char *name; //!< Name of file or interface.
+ bool promiscuous; //!< Whether the interface is in promiscuous mode.
+ //!< Only valid for live capture handles.
+ int buffer_pkts; //!< How big to make the PCAP ring buffer.
+ //!< Actual buffer size is SNAPLEN * buffer.
+ //!< Only valid for live capture handles.
+
+ pcap_t *handle; //!< libpcap handle.
+ pcap_dumper_t *dumper; //!< libpcap dumper handle.
+
+ int link_type; //!< Link layer type.
+
+ int fd; //!< Selectable file descriptor we feed to select.
+ struct pcap_stat pstats; //!< The last set of pcap stats for this handle.
+
+ fr_pcap_t *next; //!< Next handle in collection.
+};
+
+
+fr_pcap_t *fr_pcap_init(TALLOC_CTX *ctx, char const *name, fr_pcap_type_t type);
+int fr_pcap_open(fr_pcap_t *handle);
+int fr_pcap_apply_filter(fr_pcap_t *handle, char const *expression);
+char *fr_pcap_device_names(TALLOC_CTX *ctx, fr_pcap_t *handle, char c);
+ssize_t fr_pcap_link_layer_offset(uint8_t const *data, size_t len, int link_type);
+uint16_t fr_udp_checksum(uint8_t const *data, uint16_t len, uint16_t checksum,
+ struct in_addr const src_addr, struct in_addr const dst_addr);
+#endif
+
typedef void (*rad_listen_free_t)(rad_listen_t *);
typedef struct fr_protocol_t {
- uint32_t magic; //!< Used to validate loaded library
- char const *name; //!< The name of the protocol
- size_t inst_size;
- CONF_PARSER *proto_config;
+ uint64_t magic; //!< Used to validate loaded library
+ char const *name; //!< The name of the protocol
+ size_t inst_size;
+ CONF_PARSER *proto_config;
rad_listen_parse_t parse;
rad_listen_free_t free;
--- /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
+ */
+#ifndef _RADCLIENT_H
+#define _RADCLIENT_H
+/*
+ * $Id$
+ *
+ * @file radclient.h
+ * @brief Structures for the radclient utility.
+ *
+ * @copyright 2014 The FreeRADIUS server project
+ */
+#include <freeradius-devel/libradius.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Logging macros
+ */
+ #undef DEBUG
+#define DEBUG(fmt, ...) if (do_output && (fr_debug_flag > 0)) fprintf(fr_log_fp, fmt "\n", ## __VA_ARGS__)
+#undef DEBUG2
+#define DEBUG2(fmt, ...) if (do_output && (fr_debug_flag > 1)) fprintf(fr_log_fp, fmt "\n", ## __VA_ARGS__)
+
+
+#define ERROR(fmt, ...) if (do_output) fr_perror("radclient: " fmt, ## __VA_ARGS__)
+
+#define RDEBUG_ENABLED() (do_output && (fr_debug_flag > 0))
+#define RDEBUG_ENABLED2() (do_output && (fr_debug_flag > 1))
+
+#define REDEBUG(fmt, ...) if (do_output) fr_perror("(%" PRIu64 ") " fmt , request->num, ## __VA_ARGS__)
+#define RDEBUG(fmt, ...) if (do_output && (fr_debug_flag > 0)) fprintf(fr_log_fp, "(%" PRIu64 ") " fmt "\n", request->num, ## __VA_ARGS__)
+#define RDEBUG2(fmt, ...) if (do_output && (fr_debug_flag > 1)) fprintf(fr_log_fp, "(%" PRIu64 ") " fmt "\n", request->num, ## __VA_ARGS__)
+
+typedef struct rc_stats {
+ uint64_t accepted; //!< Requests to which we received a accept
+ uint64_t rejected; //!< Requests to which we received a reject
+ uint64_t lost; //!< Requests to which we received no response
+ uint64_t passed; //!< Requests which passed a filter
+ uint64_t failed; //!< Requests which failed a fitler
+} rc_stats_t;
+
+typedef struct rc_file_pair {
+ char const *packets; //!< The file containing the request packet
+ char const *filters; //!< The file containing the definition of the
+ //!< packet we want to match.
+} rc_file_pair_t;
+
+typedef struct rc_request rc_request_t;
+
+struct rc_request {
+ uint64_t num; //!< The number (within the file) of the request were reading.
+
+ rc_request_t *prev;
+ rc_request_t *next;
+
+ rc_file_pair_t *files; //!< Request and response file names.
+
+ char password[256];
+ time_t timestamp;
+
+ RADIUS_PACKET *packet; //!< The outgoing request.
+ PW_CODE packet_code; //!< The code in the outgoing request.
+ RADIUS_PACKET *reply; //!< The incoming response.
+ VALUE_PAIR *filter; //!< If the reply passes the filter, then the request passes.
+ PW_CODE filter_code; //!< Expected code of the response packet.
+
+ int resend;
+ int tries;
+ bool done; //!< Whether the request is complete.
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RADCLIENT_H */
*/
typedef enum {
- PW_TYPE_INVALID = 0, //!< Invalid (uninitialised) attribute type.
- PW_TYPE_STRING, //!< String of printable characters.
- PW_TYPE_INTEGER, //!< 32 Bit unsigned integer.
- PW_TYPE_IPADDR, //!< 32 Bit IPv4 Address.
- PW_TYPE_DATE, //!< 32 Bit Unix timestamp.
- PW_TYPE_ABINARY, //!< Ascend binary format a packed data
- //!< structure.
- PW_TYPE_OCTETS, //!< Raw octets.
- PW_TYPE_IFID, //!< Interface ID.
- PW_TYPE_IPV6ADDR, //!< 128 Bit IPv6 Address.
- PW_TYPE_IPV6PREFIX, //!< IPv6 Prefix.
- PW_TYPE_BYTE, //!< 8 Bit unsigned integer.
- PW_TYPE_SHORT, //!< 16 Bit unsigned integer.
- PW_TYPE_ETHERNET, //!< 48 Bit Mac-Address.
- PW_TYPE_SIGNED, //!< 32 Bit signed integer.
- PW_TYPE_COMBO_IP, //!< WiMAX IPv4 or IPv6 address depending
- //!< on length.
- PW_TYPE_TLV, //!< Contains nested attributes.
- PW_TYPE_EXTENDED, //!< Extended attribute space attribute.
- PW_TYPE_LONG_EXTENDED, //!< Long extended attribute space attribute.
- PW_TYPE_EVS, //!< Extended attribute, vendor specific.
- PW_TYPE_INTEGER64, //!< 64 Bit unsigned integer.
- PW_TYPE_IPV4PREFIX, //!< IPv4 Prefix.
- PW_TYPE_VSA, //!< Vendor-Specific, for attribute 26
- PW_TYPE_MAX //!< Number of defined data types.
+ PW_TYPE_INVALID = 0, //!< Invalid (uninitialised) attribute type.
+ PW_TYPE_STRING, //!< String of printable characters.
+ PW_TYPE_INTEGER, //!< 32 Bit unsigned integer.
+ PW_TYPE_IPV4_ADDR, //!< 32 Bit IPv4 Address.
+ PW_TYPE_DATE, //!< 32 Bit Unix timestamp.
+ PW_TYPE_ABINARY, //!< Ascend binary format a packed data structure.
+ PW_TYPE_OCTETS, //!< Raw octets.
+ PW_TYPE_IFID, //!< Interface ID.
+ PW_TYPE_IPV6_ADDR, //!< 128 Bit IPv6 Address.
+ PW_TYPE_IPV6_PREFIX, //!< IPv6 Prefix.
+ PW_TYPE_BYTE, //!< 8 Bit unsigned integer.
+ PW_TYPE_SHORT, //!< 16 Bit unsigned integer.
+ PW_TYPE_ETHERNET, //!< 48 Bit Mac-Address.
+ PW_TYPE_SIGNED, //!< 32 Bit signed integer.
+ PW_TYPE_IP_ADDR, //!< WiMAX IPv4 or IPv6 address depending on length.
+ PW_TYPE_TLV, //!< Contains nested attributes.
+ PW_TYPE_EXTENDED, //!< Extended attribute space attribute.
+ PW_TYPE_LONG_EXTENDED, //!< Long extended attribute space attribute.
+ PW_TYPE_EVS, //!< Extended attribute, vendor specific.
+ PW_TYPE_INTEGER64, //!< 64 Bit unsigned integer.
+ PW_TYPE_IPV4_PREFIX, //!< IPv4 Prefix.
+ PW_TYPE_VSA, //!< Vendor-Specific, for RADIUS attribute 26.
+ PW_TYPE_TIMEVAL, //!< Time value (struct timeval), only for config items.
+ PW_TYPE_BOOLEAN, //!< A truth value.
+ PW_TYPE_IP_PREFIX, //!< WiMAX IPv4 or IPv6 address prefix depending on length.
+ PW_TYPE_MAX //!< Number of defined data types.
} PW_TYPE;
-#define PW_AUTHENTICATION_REQUEST 1
-#define PW_AUTHENTICATION_ACK 2
-#define PW_AUTHENTICATION_REJECT 3
-#define PW_ACCOUNTING_REQUEST 4
-#define PW_ACCOUNTING_RESPONSE 5
-#define PW_ACCOUNTING_STATUS 6
-#define PW_PASSWORD_REQUEST 7
-#define PW_PASSWORD_ACK 8
-#define PW_PASSWORD_REJECT 9
-#define PW_ACCOUNTING_MESSAGE 10
-#define PW_ACCESS_CHALLENGE 11
-#define PW_STATUS_SERVER 12
-#define PW_STATUS_CLIENT 13
-#define PW_DISCONNECT_REQUEST 40
-#define PW_DISCONNECT_ACK 41
-#define PW_DISCONNECT_NAK 42
-#define PW_COA_REQUEST 43
-#define PW_COA_ACK 44
-#define PW_COA_NAK 45
+typedef enum {
+ PW_CODE_UNDEFINED = 0, //!< Packet code has not been set
+ PW_CODE_AUTHENTICATION_REQUEST = 1, //!< RFC2865 - Access-Request
+ PW_CODE_AUTHENTICATION_ACK = 2, //!< RFC2865 - Access-Accept
+ PW_CODE_AUTHENTICATION_REJECT = 3, //!< RFC2865 - Access-Reject
+ PW_CODE_ACCOUNTING_REQUEST = 4, //!< RFC2866 - Accounting-Request
+ PW_CODE_ACCOUNTING_RESPONSE = 5, //!< RFC2866 - Accounting-Response
+ PW_CODE_ACCOUNTING_STATUS = 6, //!< RFC3575 - Reserved
+ PW_CODE_PASSWORD_REQUEST = 7, //!< RFC3575 - Reserved
+ PW_CODE_PASSWORD_ACK = 8, //!< RFC3575 - Reserved
+ PW_CODE_PASSWORD_REJECT = 9, //!< RFC3575 - Reserved
+ PW_CODE_ACCOUNTING_MESSAGE = 10, //!< RFC3575 - Reserved
+ PW_CODE_ACCESS_CHALLENGE = 11, //!< RFC2865 - Access-Challenge
+ PW_CODE_STATUS_SERVER = 12, //!< RFC2865/RFC5997 - Status Server (request)
+ PW_CODE_STATUS_CLIENT = 13, //!< RFC2865/RFC5997 - Status Server (response)
+ PW_CODE_DISCONNECT_REQUEST = 40, //!< RFC3575/RFC5176 - Disconnect-Request
+ PW_CODE_DISCONNECT_ACK = 41, //!< RFC3575/RFC5176 - Disconnect-Ack (positive)
+ PW_CODE_DISCONNECT_NAK = 42, //!< RFC3575/RFC5176 - Disconnect-Nak (not willing to perform)
+ PW_CODE_COA_REQUEST = 43, //!< RFC3575/RFC5176 - CoA-Request
+ PW_CODE_COA_ACK = 44, //!< RFC3575/RFC5176 - CoA-Ack (positive)
+ PW_CODE_COA_NAK = 45, //!< RFC3575/RFC5176 - CoA-Nak (not willing to perform)
+ PW_CODE_MAX = 255, //!< Maximum possible code
+} PW_CODE;
#define PW_AUTH_UDP_PORT 1812
#define PW_ACCT_UDP_PORT 1813
#define PW_POD_UDP_PORT 1700
+#define PW_RADIUS_TLS_PORT 2083
#define PW_COA_UDP_PORT 3799
#define PW_USER_NAME 1
#define PW_DIGEST_RESPONSE 206
#define PW_DIGEST_ATTRIBUTES 207
-#define PW_FALL_THROUGH 500
-#define PW_RELAX_FILTER 501
-#define PW_EXEC_PROGRAM 502
-#define PW_EXEC_PROGRAM_WAIT 503
-
-#define PW_AUTH_TYPE 1000
-#define PW_PREFIX 1003
-#define PW_SUFFIX 1004
-#define PW_GROUP 1005
-#define PW_CRYPT_PASSWORD 1006
-#define PW_CONNECT_RATE 1007
-#define PW_ADD_PREFIX 1008
-#define PW_ADD_SUFFIX 1009
-#define PW_EXPIRATION 1010
-#define PW_AUTZ_TYPE 1011
-#define PW_ACCT_TYPE 1012
-#define PW_SESSION_TYPE 1013
-#define PW_POST_AUTH_TYPE 1014
-#define PW_PRE_PROXY_TYPE 1015
-#define PW_POST_PROXY_TYPE 1016
-#define PW_PRE_ACCT_TYPE 1017
-#define PW_EAP_TYPE 1018
-#define PW_EAP_TLS_REQUIRE_CLIENT_CERT 1019
-#define PW_EAP_MD5_PASSWORD 1022
-#define PW_CLIENT_SHORTNAME 1024
-#define PW_LOAD_BALANCE_KEY 1025
-#define PW_RAW_ATTRIBUTE 1026
-#define PW_TNC_VLAN_ACCESS 1027
-#define PW_TNC_VLAN_ISOLATE 1028
-#define PW_USER_CATEGORY 1029
-#define PW_GROUP_NAME 1030
-#define PW_HUNTGROUP_NAME 1031
-#define PW_SIMULTANEOUS_USE 1034
-#define PW_STRIP_USER_NAME 1035
-#define PW_HINT 1040
-#define PAM_AUTH_ATTR 1041
-#define PW_LOGIN_TIME 1042
-#define PW_STRIPPED_USER_NAME 1043
-#define PW_CURRENT_TIME 1044
-#define PW_REALM 1045
-#define PW_NO_SUCH_ATTRIBUTE 1046
-#define PW_PACKET_TYPE 1047
-#define PW_PROXY_TO_REALM 1048
-#define PW_REPLICATE_TO_REALM 1049
-#define PW_ACCT_SESSION_START_TIME 1050
-#define PW_ACCT_UNIQUE_SESSION_ID 1051
-#define PW_CLIENT_IP_ADDRESS 1052
-#define PW_LDAP_USERDN 1053
-#define PW_NS_MTA_MD5_PASSWORD 1054
-#define PW_SQL_USER_NAME 1055
-#define PW_LM_PASSWORD 1057
-#define PW_NT_PASSWORD 1058
-#define PW_SMB_ACCOUNT_CTRL 1059
-#define PW_SMB_ACCOUNT_CTRL_TEXT 1061
-#define PW_USER_PROFILE 1062
-#define PW_DIGEST_REALM 1063
-#define PW_DIGEST_NONCE 1064
-#define PW_DIGEST_METHOD 1065
-#define PW_DIGEST_URI 1066
-#define PW_DIGEST_QOP 1067
-#define PW_DIGEST_ALGORITHM 1068
-#define PW_DIGEST_BODY_DIGEST 1069
-#define PW_DIGEST_CNONCE 1070
-#define PW_DIGEST_NONCE_COUNT 1071
-#define PW_DIGEST_USER_NAME 1072
-#define PW_POOL_NAME 1073
-#define PW_LDAP_GROUP 1074
-#define PW_MODULE_SUCCESS_MESSAGE 1075
-#define PW_MODULE_FAILURE_MESSAGE 1076
-#if 0 /* no longer used */
-#define PW_X99_FAST 1077
-#endif
-#define PW_REWRITE_RULE 1078
-#define PW_SQL_GROUP 1079
-#define PW_RESPONSE_PACKET_TYPE 1080
-#define PW_DIGEST_HA1 1081
-#define PW_MS_CHAP_USE_NTLM_AUTH 1082
-#define PW_MS_CHAP_USER_NAME 1083
-#define PW_PACKET_SRC_IP_ADDRESS 1084
-#define PW_PACKET_DST_IP_ADDRESS 1085
-#define PW_PACKET_SRC_PORT 1086
-#define PW_PACKET_DST_PORT 1087
-#define PW_PACKET_AUTHENTICATION_VECTOR 1088
-#define PW_TIME_OF_DAY 1089
-#define PW_REQUEST_PROCESSING_STAGE 1090
-
-#define PW_SHA_PASSWORD 1093
-#define PW_SSHA_PASSWORD 1094
-#define PW_MD5_PASSWORD 1095
-#define PW_SMD5_PASSWORD 1096
-
-#define PW_PACKET_SRC_IPV6_ADDRESS 1097
-#define PW_PACKET_DST_IPV6_ADDRESS 1098
-#define PW_VIRTUAL_SERVER 1099
-#define PW_CLEARTEXT_PASSWORD 1100
-#define PW_PASSWORD_WITH_HEADER 1101
-#define PW_SEND_COA_REQUEST 1107
-#define PW_MODULE_RETURN_CODE 1108
-#define PW_PACKET_ORIGINAL_TIMESTAMP 1109
-#define PW_HOME_SERVER_POOL 1111
-#define PW_FREERADIUS_CLIENT_IP_ADDRESS 1120
-#define PW_FREERADIUS_CLIENT_IPV6_ADDRESS 1121
-#define PW_RECV_COA_TYPE 1131
-#define PW_SEND_COA_TYPE 1132
-#define PW_MSCHAP_PASSWORD 1133
-#define PW_PACKET_TRANSMIT_COUNTER 1134
-#define PW_CACHED_SESSION_POLICY 1135
-#define PW_FREERADIUS_CLIENT_SRC_IP_ADDRESS 1143
-#define PW_FREERADIUS_CLIENT_SRC_IPV6_ADDRESS 1144
-
-#define PW_OTP_CHALLENGE 1145
-#define PW_EAP_SESSION_ID 1146
+/*
+ * All internal attributes are now defined in this file.
+ */
+#include <freeradius-devel/attributes.h>
#define PW_CHBIND_RESPONSE_CODE 1147
/*
#include <freeradius-devel/connection.h>
#include <freeradius-devel/map.h>
-typedef struct request REQUEST;
+typedef struct rad_request REQUEST;
#include <freeradius-devel/log.h>
# include <sys/wait.h>
#endif
-#ifdef HAVE_PCREPOSIX_H
-# include <pcreposix.h>
-#else
-# ifdef HAVE_REGEX_H
-# include <regex.h>
-
-/*
- * For POSIX Regular expressions.
- * (0) Means no extended regular expressions.
- * REG_EXTENDED means use extended regular expressions.
- */
-# ifndef REG_EXTENDED
-# define REG_EXTENDED (0)
-# endif
-
-# ifndef REG_NOSUB
-# define REG_NOSUB (0)
-# endif
-# endif
-#endif
-
#ifndef NDEBUG
# define REQUEST_MAGIC (0xdeadbeef)
#endif
#include <freeradius-devel/stats.h>
#include <freeradius-devel/realms.h>
-#ifdef WITH_COMMAND_SOCKET
-# define PW_RADMIN_PORT 18120
-#endif
-
#ifdef __cplusplus
extern "C" {
#endif
typedef struct radclient {
fr_ipaddr_t ipaddr;
fr_ipaddr_t src_ipaddr;
- int prefix;
char const *longname;
char const *secret;
char const *shortname;
bool message_authenticator;
- char *nas_type;
- char *login;
- char *password;
- char *server;
+ char const *nas_type;
+ char const *login;
+ char const *password;
+ char const *server;
int number; /* internal use only */
CONF_SECTION const *cs;
#ifdef WITH_STATS
#endif
#endif
+ struct timeval response_window;
+
int proto;
#ifdef WITH_TCP
fr_socket_limit_t limit;
#endif
#ifdef WITH_DYNAMIC_CLIENTS
- int lifetime;
- int dynamic; /* was dynamically defined */
+ uint32_t lifetime;
+ uint32_t dynamic; /* was dynamically defined */
time_t created;
time_t last_new_client;
- char *client_server;
+ char const *client_server;
bool rate_limit;
#endif
#ifdef WITH_COA
- char *coa_name;
- home_server *coa_server;
+ char const *coa_name;
+ home_server_t *coa_server;
home_pool_t *coa_pool;
#endif
} RADCLIENT;
RAD_LISTEN_MAX
} RAD_LISTEN_TYPE;
+/** Return codes indicating the result of the module call
+ *
+ * All module functions must return one of the codes listed below (apart from
+ * RLM_MODULE_NUMCODES, which is used to check for validity).
+ */
+typedef enum rlm_rcodes {
+ RLM_MODULE_REJECT = 0, //!< Immediately reject the request.
+ RLM_MODULE_FAIL, //!< Module failed, don't reply.
+ RLM_MODULE_OK, //!< The module is OK, continue.
+ RLM_MODULE_HANDLED, //!< The module handled the request, so stop.
+ RLM_MODULE_INVALID, //!< The module considers the request invalid.
+ RLM_MODULE_USERLOCK, //!< Reject the request (user is locked out).
+ RLM_MODULE_NOTFOUND, //!< User not found.
+ RLM_MODULE_NOOP, //!< Module succeeded without doing anything.
+ RLM_MODULE_UPDATED, //!< OK (pairs modified).
+ RLM_MODULE_NUMCODES, //!< How many valid return codes there are.
+ RLM_MODULE_UNKNOWN //!< Error resolving rcode (should not be
+ //!< returned by modules).
+} rlm_rcode_t;
+extern const FR_NAME_NUMBER modreturn_table[];
/*
* For listening on multiple IP's and ports.
#define VERIFY_REQUEST(_x)
#endif
-struct request {
+typedef enum {
+ REQUEST_ACTIVE = 1,
+ REQUEST_STOP_PROCESSING,
+ REQUEST_COUNTED
+} rad_master_state_t;
+#define REQUEST_MASTER_NUM_STATES (REQUEST_COUNTED + 1)
+
+typedef enum {
+ REQUEST_QUEUED = 1,
+ REQUEST_RUNNING,
+ REQUEST_PROXIED,
+ REQUEST_RESPONSE_DELAY,
+ REQUEST_CLEANUP_DELAY,
+ REQUEST_DONE
+} rad_child_state_t;
+#define REQUEST_CHILD_NUM_STATES (REQUEST_DONE + 1)
+
+struct rad_request {
#ifndef NDEBUG
- uint32_t magic; //!< Magic number used to
- //!< detect memory corruption,
- //!< or request structs that
- //!< have not been properly
- //!< initialised.
+ uint32_t magic; //!< Magic number used to detect memory corruption,
+ //!< or request structs that have not been properly initialised.
#endif
RADIUS_PACKET *packet; //!< Incoming request.
#ifdef WITH_PROXY
#ifdef WITH_PROXY
RADIUS_PACKET *proxy_reply; //!< Incoming response.
#endif
- VALUE_PAIR *config_items; //!< VALUE_PAIR s used to set
- //!< per request parameters for
- //!< modules and the server
- //!< core at runtime.
+ VALUE_PAIR *config_items; //!< VALUE_PAIRs used to set per request parameters
+ //!< for modules and the server core at runtime.
VALUE_PAIR *username; //!< Cached username VALUE_PAIR.
VALUE_PAIR *password; //!< Cached password VALUE_PAIR.
- fr_request_process_t process; //!< The function to call to
- //!< move the request through
- //!< the state machine.
+ fr_request_process_t process; //!< The function to call to move the request through the state machine.
- RAD_REQUEST_FUNP handle; //!< The function to call to
- //!< move the request through
- //!< the various server
- //!< configuration sections.
+ RAD_REQUEST_FUNP handle; //!< The function to call to move the request through the
+ //!< various server configuration sections.
- struct main_config_t *root; //!< Pointer to the main config
- //!< hack to try and deal with
- //!< hup.
+ struct main_config_t *root; //!< Pointer to the main config hack to try and deal with hup.
request_data_t *data; //!< Request metadata.
- RADCLIENT *client; //!< The client that originally
- //!< sent us the request.
+ RADCLIENT *client; //!< The client that originally sent us the request.
#ifdef HAVE_PTHREAD_H
- pthread_t child_pid; //!< Current thread handling
- //!< the request.
+ pthread_t child_pid; //!< Current thread handling the request.
#endif
- time_t timestamp; //!< When the request was
- //!< received.
- unsigned int number; //!< Monotonically increasing
- //!< request number. Reset on
- //!< server restart.
+ time_t timestamp; //!< When the request was received.
+ unsigned int number; //!< Monotonically increasing request number. Reset on server restart.
- rad_listen_t *listener; //!< The listener that received
- //!< the request.
+ rad_listen_t *listener; //!< The listener that received the request.
#ifdef WITH_PROXY
- rad_listen_t *proxy_listener;//!< Listener for outgoing
- //!< requests.
+ rad_listen_t *proxy_listener;//!< Listener for outgoing requests.
#endif
+ rlm_rcode_t rcode; //!< Last rcode returned by a module
- int simul_max; //!< Maximum number of
- //!< concurrent sessions for
- //!< this user.
+ int simul_max; //!< Maximum number of concurrent sessions for this user.
#ifdef WITH_SESSION_MGMT
- int simul_count; //!< The current number of
- //!< sessions for this user.
- int simul_mpp; //!< WEIRD: 1 is false,
- //!< 2 is true.
+ int simul_count; //!< The current number of sessions for this user.
+ int simul_mpp; //!< WEIRD: 1 is false, 2 is true.
#endif
- log_debug_t options; //!< Request options, currently
- //!< just holds the debug level
- //!< for the request.
-
- char const *module; //!< Module the request is
- //!< currently being processed
- //!< by.
- char const *component; //!< Section the request is
- //!< in.
+ char const *module; //!< Module the request is currently being processed by.
+ char const *component; //!< Section the request is in.
int delay;
- int master_state;
- int child_state;
+ rad_master_state_t master_state;
+ rad_child_state_t child_state;
RAD_LISTEN_TYPE priority;
+ int response_delay;
int timer_action;
fr_event_t *ev;
- int in_request_hash;
+ bool in_request_hash;
#ifdef WITH_PROXY
- int in_proxy_hash;
+ bool in_proxy_hash;
- home_server *home_server;
- home_pool_t *home_pool; /* for dynamic failover */
+ home_server_t *home_server;
+ home_pool_t *home_pool; //!< For dynamic failover
struct timeval proxy_retransmit;
- int num_proxied_requests;
- int num_proxied_responses;
+ uint32_t num_proxied_requests;
+ uint32_t num_proxied_responses;
#endif
char const *server;
REQUEST *parent;
- radlog_func_t radlog; //!< Function to call to output
- //!< log messages about this
+
+ struct {
+ radlog_func_t func; //!< Function to call to output log messages about this
//!< request.
+
+ log_debug_t lvl; //!< Request options, currently just holds the debug level or
+ //!< the request.
+
+ uint8_t indent; //!< By how much to indent log messages. uin8_t so it's obvious
+ //!< when a request has been exdented too much.
+ } log;
+
#ifdef WITH_COA
- REQUEST *coa; //!< CoA request originated
- //!< by this request.
- int num_coa_requests;//!< Counter for number of
- //!< requests sent including
+ REQUEST *coa; //!< CoA request originated by this request.
+ uint32_t num_coa_requests;//!< Counter for number of requests sent including
//!< retransmits.
#endif
}; /* REQUEST typedef */
-#define RAD_REQUEST_OPTION_NONE (0)
-#define RAD_REQUEST_OPTION_DEBUG (1)
-#define RAD_REQUEST_OPTION_DEBUG2 (2)
-#define RAD_REQUEST_OPTION_DEBUG3 (3)
-#define RAD_REQUEST_OPTION_DEBUG4 (4)
-
-#define REQUEST_ACTIVE (1)
-#define REQUEST_STOP_PROCESSING (2)
-#define REQUEST_COUNTED (3)
-
-#define REQUEST_QUEUED (1)
-#define REQUEST_RUNNING (2)
-#define REQUEST_PROXIED (3)
-#define REQUEST_REJECT_DELAY (4)
-#define REQUEST_CLEANUP_DELAY (5)
-#define REQUEST_DONE (6)
+#define RAD_REQUEST_OPTION_NONE (0)
+#define RAD_REQUEST_OPTION_DEBUG (1)
+#define RAD_REQUEST_OPTION_DEBUG2 (2)
+#define RAD_REQUEST_OPTION_DEBUG3 (3)
+#define RAD_REQUEST_OPTION_DEBUG4 (4)
typedef struct radclient_list RADCLIENT_LIST;
#endif
bool nodup;
bool synchronous;
- int workers;
+ uint32_t workers;
#ifdef WITH_TLS
fr_tls_server_conf_t *tls;
* For normal sockets.
*/
fr_ipaddr_t my_ipaddr;
- int my_port;
+ uint16_t my_port;
char const *interface;
#ifdef SO_BROADCAST
int broadcast;
#endif
time_t rate_time;
- int rate_pps_old;
- int rate_pps_now;
- int max_rate;
+ uint32_t rate_pps_old;
+ uint32_t rate_pps_now;
+ uint32_t max_rate;
/* for outgoing sockets */
- home_server *home;
+ home_server_t *home;
fr_ipaddr_t other_ipaddr;
- int other_port;
+ uint16_t other_port;
int proto;
#ifdef WITH_TCP
- /* for a proxy connecting to home servers */
+ /* for a proxy connecting to home servers */
time_t last_packet;
time_t opened;
fr_event_t *ev;
VALUE_PAIR *certs;
pthread_mutex_t mutex;
uint8_t *data;
+ size_t partial;
#endif
RADCLIENT_LIST *clients;
typedef struct main_config_t {
struct main_config *next;
fr_ipaddr_t myip; /* from the command-line only */
- int port; /* from the command-line only */
+ uint16_t port; /* from the command-line only */
bool log_auth;
bool log_auth_badpass;
bool log_auth_goodpass;
bool allow_core_dumps;
- int debug_level;
+ uint32_t debug_level;
+ bool daemonize;
#ifdef WITH_PROXY
bool proxy_requests;
#endif
- int reject_delay;
+ uint32_t reject_delay;
bool status_server;
- int max_request_time;
- int cleanup_delay;
- int max_requests;
-#ifdef DELETE_BLOCKED_REQUESTS
- int kill_unresponsive_children;
-#endif
- char *log_file;
+ char const *allow_vulnerable_openssl;
+
+ uint32_t max_request_time;
+ uint32_t cleanup_delay;
+ uint32_t max_requests;
+ char const *log_file;
char const *dictionary_dir;
- char *checkrad;
+ char const *checkrad;
char const *pid_file;
rad_listen_t *listen;
int syslog_facility;
char const *name;
char const *auth_badpass_msg;
char const *auth_goodpass_msg;
- int debug_memory;
+ bool debug_memory;
+ bool memory_report;
+ char const *panic_action;
+ char const *denied_msg;
+ struct timeval init_delay; /* initial request processing delay */
} MAIN_CONFIG_T;
#define SECONDS_PER_DAY 86400
#define MAX_REQUEST_TIME 30
#define CLEANUP_DELAY 5
#define MAX_REQUESTS 256
-#define RETRY_DELAY 5
-#define RETRY_COUNT 3
-#define DEAD_TIME 120
-#define EXEC_TIMEOUT 10
+#define RETRY_DELAY 5
+#define RETRY_COUNT 3
+#define DEAD_TIME 120
+#define EXEC_TIMEOUT 10
/* for paircompare_register */
typedef int (*RAD_COMPARE_FUNC)(void *instance, REQUEST *,VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR **);
REQUEST_FAIL_DECODE, //!< Rad_decode didn't like it.
REQUEST_FAIL_PROXY, //!< Call to proxy modules failed.
REQUEST_FAIL_PROXY_SEND, //!< Proxy_send didn't like it.
- REQUEST_FAIL_NO_RESPONSE, //!< We weren't told to respond,
- //!< so we reject.
+ REQUEST_FAIL_NO_RESPONSE, //!< We weren't told to respond, so we reject.
REQUEST_FAIL_HOME_SERVER, //!< The home server didn't respond.
REQUEST_FAIL_HOME_SERVER2, //!< Another case of the above.
REQUEST_FAIL_HOME_SERVER3, //!< Another case of the above.
REQUEST_FAIL_NORMAL_REJECT, //!< Authentication failure.
- REQUEST_FAIL_SERVER_TIMEOUT //!< The server took too long to
- //!< process the request.
+ REQUEST_FAIL_SERVER_TIMEOUT //!< The server took too long to process the request.
} request_fail_t;
/*
extern char const *radacct_dir;
extern char const *radlog_dir;
extern char const *radlib_dir;
-extern char const *radius_dir;
extern char const *radius_libdir;
extern uint32_t expiration_seconds;
extern bool log_stripped_names;
extern char const *radiusd_version;
void radius_signal_self(int flag);
-#define RADIUS_SIGNAL_SELF_NONE (0)
-#define RADIUS_SIGNAL_SELF_HUP (1 << 0)
-#define RADIUS_SIGNAL_SELF_TERM (1 << 1)
-#define RADIUS_SIGNAL_SELF_EXIT (1 << 2)
-#define RADIUS_SIGNAL_SELF_DETAIL (1 << 3)
-#define RADIUS_SIGNAL_SELF_NEW_FD (1 << 4)
-#define RADIUS_SIGNAL_SELF_MAX (1 << 5)
-
+typedef enum {
+ RADIUS_SIGNAL_SELF_NONE = (0),
+ RADIUS_SIGNAL_SELF_HUP = (1 << 0),
+ RADIUS_SIGNAL_SELF_TERM = (1 << 1),
+ RADIUS_SIGNAL_SELF_EXIT = (1 << 2),
+ RADIUS_SIGNAL_SELF_DETAIL = (1 << 3),
+ RADIUS_SIGNAL_SELF_NEW_FD = (1 << 4),
+ RADIUS_SIGNAL_SELF_MAX = (1 << 5)
+} radius_signal_t;
/*
* Function prototypes.
*/
int rad_accounting(REQUEST *);
/* session.c */
-int rad_check_ts(uint32_t nasaddr, unsigned int port, char const *user,
- char const *sessionid);
+int rad_check_ts(uint32_t nasaddr, uint32_t nas_port, char const *user, char const *sessionid);
int session_zap(REQUEST *request, uint32_t nasaddr,
- unsigned int port, char const *user,
+ uint32_t nas_port, char const *user,
char const *sessionid, uint32_t cliaddr,
- char proto,int session_time);
+ char proto, int session_time);
/* radiusd.c */
#undef debug_pair
void request_free(REQUEST **request);
int request_opaque_free(REQUEST *request);
int rad_mkdir(char *directory, mode_t mode);
-int rad_checkfilename(char const *filename);
-int rad_file_exists(char const *filename);
void *rad_malloc(size_t size); /* calls exit(1) on error! */
-void *rad_calloc(size_t size); /* calls exit(1) on error! */
void rad_const_free(void const *ptr);
REQUEST *request_alloc(TALLOC_CTX *ctx);
REQUEST *request_alloc_fake(REQUEST *oldreq);
int rad_copy_string(char *dst, char const *src);
int rad_copy_string_bare(char *dst, char const *src);
int rad_copy_variable(char *dst, char const *from);
-int rad_pps(int *past, int *present, time_t *then,
- struct timeval *now);
+uint32_t rad_pps(uint32_t *past, uint32_t *present, time_t *then, struct timeval *now);
int rad_expand_xlat(REQUEST *request, char const *cmd,
int max_argc, char *argv[], bool can_fail,
size_t argv_buflen, char *argv_buf);
void rad_regcapture(REQUEST *request, int compare, char const *value,
regmatch_t rxmatch[]);
+void verify_request(REQUEST *request); /* only for special debug builds */
/* client.c */
RADCLIENT_LIST *clients_init(CONF_SECTION *cs);
int client_add(RADCLIENT_LIST *clients, RADCLIENT *client);
#ifdef WITH_DYNAMIC_CLIENTS
void client_delete(RADCLIENT_LIST *clients, RADCLIENT *client);
-RADCLIENT *client_from_query(TALLOC_CTX *ctx, char const *identifier, char const *secret, char const *shortname,
- char const *type, char const *server, bool require_ma);
RADCLIENT *client_from_request(RADCLIENT_LIST *clients, REQUEST *request);
#endif
+RADCLIENT *client_from_query(TALLOC_CTX *ctx, char const *identifier, char const *secret, char const *shortname,
+ char const *type, char const *server, bool require_ma) CC_HINT(nonnull(2, 3));
+
RADCLIENT *client_find(RADCLIENT_LIST const *clients,
fr_ipaddr_t const *ipaddr, int proto);
void pairlist_free(PAIR_LIST **);
/* version.c */
-int ssl_check_version(void);
+int rad_check_lib_magic(uint64_t magic);
+int ssl_check_consistency(void);
+char const *ssl_version_by_num(uint64_t version);
+char const *ssl_version_range(uint64_t low, uint64_t high);
char const *ssl_version(void);
void version(void);
/* auth.c */
-char *auth_name(char *buf, size_t buflen, REQUEST *request, int do_cli);
+char *auth_name(char *buf, size_t buflen, REQUEST *request, bool do_cli);
int rad_authenticate (REQUEST *);
int rad_postauth(REQUEST *);
int rad_virtual_server(REQUEST *);
/* exec.c */
-pid_t radius_start_program(char const *cmd, REQUEST *request,
- int exec_wait,
- int *input_fd,
- int *output_fd,
- VALUE_PAIR *input_pairs,
- int shell_escape);
+pid_t radius_start_program(char const *cmd, REQUEST *request, bool exec_wait,
+ int *input_fd, int *output_fd,
+ VALUE_PAIR *input_pairs, bool shell_escape);
int radius_readfrom_program(REQUEST *request, int fd, pid_t pid, int timeout,
char *answer, int left);
int radius_exec_program(REQUEST *request, char const *cmd, bool exec_wait, bool shell_escape,
char *user_msg, size_t msg_len, int timeout,
VALUE_PAIR *input_pairs, VALUE_PAIR **output_pairs);
-void exec_trigger(REQUEST *request, CONF_SECTION *cs, char const *name, int quench);
+void exec_trigger(REQUEST *request, CONF_SECTION *cs, char const *name, int quench)
+ CC_HINT(nonnull (3));
/* valuepair.c */
int paircompare_register(DICT_ATTR const *attribute, DICT_ATTR const *from,
- bool first_only, RAD_COMPARE_FUNC func, void *instance);
+ bool first_only, RAD_COMPARE_FUNC func, void *instance);
void paircompare_unregister(DICT_ATTR const *attr, RAD_COMPARE_FUNC func);
void paircompare_unregister_instance(void *instance);
int paircompare(REQUEST *request, VALUE_PAIR *req_list,
VALUE_PAIR *check, VALUE_PAIR **rep_list);
+value_pair_tmpl_t *radius_xlat2tmpl(TALLOC_CTX *ctx, xlat_exp_t *xlat);
int radius_xlat_do(REQUEST *request, VALUE_PAIR *vp);
-void radius_xlat_move(REQUEST *, VALUE_PAIR **to, VALUE_PAIR **from);
int radius_compare_vps(REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *vp);
int radius_callback_compare(REQUEST *request, VALUE_PAIR *req,
VALUE_PAIR *check, VALUE_PAIR *check_pairs,
VALUE_PAIR **reply_pairs);
int radius_find_compare(DICT_ATTR const *attribute);
-VALUE_PAIR *radius_paircreate(REQUEST *request, VALUE_PAIR **vps,
- unsigned int attribute, unsigned int vendor);
-void module_failure_msg(REQUEST *request, char const *fmt, ...)
-#ifdef __GNUC__
- __attribute__ ((format (printf, 2, 3)))
-#endif
-;
+VALUE_PAIR *radius_paircreate(TALLOC_CTX *ctx, VALUE_PAIR **vps, unsigned int attribute, unsigned int vendor);
+
+void module_failure_msg(REQUEST *request, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
+void vmodule_failure_msg(REQUEST *request, char const *fmt, va_list ap) CC_HINT(format (printf, 2, 0));
/*
- * Less code == less bugs
+ * Less code == fewer bugs
+ *
+ * @param _a attribute
+ * @param _b value
+ * @param _c op
*/
#define pairmake_packet(_a, _b, _c) pairmake(request->packet, &request->packet->vps, _a, _b, _c)
#define pairmake_reply(_a, _b, _c) pairmake(request->reply, &request->reply->vps, _a, _b, _c)
typedef size_t (*RADIUS_ESCAPE_STRING)(REQUEST *, char *out, size_t outlen, char const *in, void *arg);
ssize_t radius_xlat(char *out, size_t outlen, REQUEST *request, char const *fmt, RADIUS_ESCAPE_STRING escape,
- void *escape_ctx);
+ void *escape_ctx)
+ CC_HINT(nonnull (1 ,3 ,4));
+
+ssize_t radius_axlat(char **out, REQUEST *request, char const *fmt, RADIUS_ESCAPE_STRING escape, void *escape_ctx)
+ CC_HINT(nonnull (1, 2, 3));
-ssize_t radius_axlat(char **out, REQUEST *request, char const *fmt, RADIUS_ESCAPE_STRING escape,
- void *escape_ctx);
+ssize_t radius_axlat_struct(char **out, REQUEST *request, xlat_exp_t const *xlat, RADIUS_ESCAPE_STRING escape,
+ void *ctx)
+ CC_HINT(nonnull (1, 2, 3));
typedef ssize_t (*RAD_XLAT_FUNC)(void *instance, REQUEST *, char const *, char *, size_t);
int xlat_register(char const *module, RAD_XLAT_FUNC func, RADIUS_ESCAPE_STRING escape,
void *instance);
-void xlat_unregister(char const *module, RAD_XLAT_FUNC func,
- void *instance);
+void xlat_unregister(char const *module, RAD_XLAT_FUNC func, void *instance);
+ssize_t xlat_fmt_to_ref(uint8_t const **out, REQUEST *request, char const *fmt);
void xlat_free(void);
/* threads.c */
-extern int thread_pool_init(CONF_SECTION *cs, int *spawn_flag);
-extern void thread_pool_stop(void);
-extern int thread_pool_addrequest(REQUEST *, RAD_REQUEST_FUNP);
-extern pid_t rad_fork(void);
-extern pid_t rad_waitpid(pid_t pid, int *status);
-extern int total_active_threads(void);
-extern void thread_pool_lock(void);
-extern void thread_pool_unlock(void);
-extern void thread_pool_queue_stats(int array[RAD_LISTEN_MAX], int pps[2]);
+extern int thread_pool_init(CONF_SECTION *cs, bool *spawn_flag);
+extern void thread_pool_stop(void);
+extern int thread_pool_addrequest(REQUEST *, RAD_REQUEST_FUNP);
+extern pid_t rad_fork(void);
+extern pid_t rad_waitpid(pid_t pid, int *status);
+extern int total_active_threads(void);
+extern void thread_pool_lock(void);
+extern void thread_pool_unlock(void);
+extern void thread_pool_queue_stats(int array[RAD_LISTEN_MAX], int pps[2]);
#ifndef HAVE_PTHREAD_H
#define rad_fork(n) fork()
#define rad_waitpid(a,b) waitpid(a,b, 0)
#endif
-/* mainconfig.c */
+/* main_config.c */
/* Define a global config structure */
-extern struct main_config_t mainconfig;
+extern struct main_config_t main_config;
-int read_mainconfig(int reload);
-int free_mainconfig(void);
-void hup_mainconfig(void);
+void set_radius_dir(TALLOC_CTX *ctx, char const *path);
+char const *get_radius_dir(void);
+int main_config_init(void);
+int main_config_free(void);
+void main_config_hup(void);
void hup_logfile(void);
void fr_suid_down(void);
void fr_suid_up(void);
/* listen.c */
void listen_free(rad_listen_t **head);
-int listen_init(CONF_SECTION *cs, rad_listen_t **head, int spawn_flag);
-rad_listen_t *proxy_new_listener(home_server *home, int src_port);
-RADCLIENT *client_listener_find(rad_listen_t *listener,
- fr_ipaddr_t const *ipaddr, int src_port);
+int listen_init(CONF_SECTION *cs, rad_listen_t **head, bool spawn_flag);
+rad_listen_t *proxy_new_listener(home_server_t *home, uint16_t src_port);
+RADCLIENT *client_listener_find(rad_listen_t *listener, fr_ipaddr_t const *ipaddr, uint16_t src_port);
#ifdef WITH_STATS
-RADCLIENT_LIST *listener_find_client_list(fr_ipaddr_t const *ipaddr,
- int port);
+RADCLIENT_LIST *listener_find_client_list(fr_ipaddr_t const *ipaddr, uint16_t port);
#endif
-rad_listen_t *listener_find_byipaddr(fr_ipaddr_t const *ipaddr, int port,
- int proto);
+rad_listen_t *listener_find_byipaddr(fr_ipaddr_t const *ipaddr, uint16_t port, int proto);
int rad_status_server(REQUEST *request);
/* event.c */
-int radius_event_init(CONF_SECTION *cs, int spawn_flag);
+typedef enum event_corral_t {
+ EVENT_CORRAL_MAIN = 0, //!< Always main thread event list
+ EVENT_CORRAL_AUX //!< Maybe main thread or one shared by modules
+} event_corral_t;
+
+fr_event_list_t *radius_event_list_corral(event_corral_t hint);
+int radius_event_init(TALLOC_CTX *ctx);
+int radius_event_start(CONF_SECTION *cs, bool spawn_flag);
void radius_event_free(void);
int radius_event_process(void);
-int event_new_fd(rad_listen_t *listener);
+void radius_update_listener(rad_listen_t *listener);
void revive_home_server(void *ctx);
-void mark_home_server_dead(home_server *home, struct timeval *when);
+void mark_home_server_dead(home_server_t *home, struct timeval *when);
/* evaluate.c */
typedef struct fr_cond_t fr_cond_t;
fr_cond_t const *c);
int radius_evaluate_cond(REQUEST *request, int modreturn, int depth,
fr_cond_t const *c);
-void radius_pairmove(REQUEST *request, VALUE_PAIR **to, VALUE_PAIR *from);
+void radius_pairmove(REQUEST *request, VALUE_PAIR **to, VALUE_PAIR *from, bool do_xlat) CC_HINT(nonnull);
VALUE_PAIR **radius_list(REQUEST *request, pair_lists_t list);
+TALLOC_CTX *radius_list_ctx(REQUEST *request, pair_lists_t list_name);
pair_lists_t radius_list_name(char const **name, pair_lists_t unknown);
int radius_request(REQUEST **request, request_refs_t name);
request_refs_t radius_request_name(char const **name, request_refs_t unknown);
int radius_mapexec(VALUE_PAIR **out, REQUEST *request, value_pair_map_t const *map);
-int radius_map2vp(VALUE_PAIR **out, REQUEST *request, value_pair_map_t const *map, void *ctx);
-int radius_map2request(REQUEST *request, value_pair_map_t const *map,
- char const *src, radius_tmpl_getvalue_t func, void *ctx);
-
-int radius_str2vp(REQUEST *request, char const *raw,
- request_refs_t dst_request_def, pair_lists_t dst_list_def,
- request_refs_t src_request_def, pair_lists_t src_list_def);
-VALUE_PAIR *radius_vpt_get_vp(REQUEST *request, value_pair_tmpl_t const *vpt);
-int radius_get_vp(VALUE_PAIR **vp_p, REQUEST *request, char const *name);
+int radius_map2vp(VALUE_PAIR **out, REQUEST *request, value_pair_map_t const *map, void *ctx) CC_HINT(nonnull (1,2,3));
+void radius_map_debug(REQUEST *request, value_pair_map_t const *map, VALUE_PAIR const *vp) CC_HINT(nonnull(1, 2));
+int radius_map2request(REQUEST *request, value_pair_map_t const *map, radius_tmpl_getvalue_t func, void *ctx);
+
+int radius_strpair2map(value_pair_map_t **out, REQUEST *request, char const *raw,
+ request_refs_t dst_request_def, pair_lists_t dst_list_def,
+ request_refs_t src_request_def, pair_lists_t src_list_def);
+bool radius_map_dst_valid(REQUEST *request, value_pair_map_t const *map);
+int radius_tmpl_get_vp(VALUE_PAIR **out, REQUEST *request, value_pair_tmpl_t const *vpt);
+int radius_get_vp(VALUE_PAIR **out, REQUEST *request, char const *name);
+int radius_tmpl_copy_vp(VALUE_PAIR **out, REQUEST *request, value_pair_tmpl_t const *vpt);
+int radius_copy_vp(VALUE_PAIR **out, REQUEST *request, char const *name);
#ifdef WITH_TLS
/*
int proxy_tls_send(rad_listen_t *listener, REQUEST *request);
#endif
+/*
+ * For radmin over TCP.
+ */
+#define PW_RADMIN_PORT 18120
+
#ifdef __cplusplus
}
#endif
/*
- * radsniff.h Structures and defines for the RADIUS sniffer.
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 if the
+ * License as published by the Free Software Foundation.
*
- * Version: $Id$
+ * 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.
*
- * 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
+ * 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
+ */
+
+/**
+ * $Id$
+ * @file radsniff.h
+ * @brief Structures and prototypes for the RADIUS sniffer.
*
- * Copyright 2006 The FreeRADIUS server project
- * Copyright 2006 Nicolas Baradakis <nicolas.baradakis@cegetel.net>
+ * @copyright 2013 Arran Cudbard-Bell <arran.cudbardb@freeradius.org>
+ * @copyright 2006 The FreeRADIUS server project
+ * @copyright 2006 Nicolas Baradakis <nicolas.baradakis@cegetel.net>
*/
RCSIDH(radsniff_h, "$Id$")
#include <sys/types.h>
#include <netinet/in.h>
+#include <pcap/pcap.h>
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/pcap.h>
+#include <freeradius-devel/event.h>
+
+#ifdef HAVE_COLLECTDC_H
+# include <collectd/client.h>
+#endif
+
+#define RS_DEFAULT_PREFIX "radsniff" //!< Default instance
+#define RS_DEFAULT_SECRET "testing123" //!< Default secret
+#define RS_DEFAULT_TIMEOUT 5200 //!< Standard timeout of 5s + 300ms to cover network latency
+#define RS_FORCE_YIELD 1000 //!< Service another descriptor every X number of packets
+#define RS_RETRANSMIT_MAX 5 //!< Maximum number of times we expect to see a packet retransmitted
+#define RS_MAX_ATTRS 50 //!< Maximum number of attributes we can filter on.
+#define RS_SOCKET_REOPEN_DELAY 5000 //!< How long we delay re-opening a collectd socket.
+
/*
- * The number of bytes in an ethernet (MAC) address.
+ * Logging macros
*/
-#define ETHER_ADDR_LEN 6
+#undef DEBUG2
+#define DEBUG2(fmt, ...) if (fr_debug_flag > 2) fprintf(fr_log_fp , fmt "\n", ## __VA_ARGS__)
+#undef DEBUG
+#define DEBUG(fmt, ...) if (fr_debug_flag > 1) fprintf(fr_log_fp , fmt "\n", ## __VA_ARGS__)
+#undef INFO
+#define INFO(fmt, ...) if (fr_debug_flag > 0) fprintf(fr_log_fp , fmt "\n", ## __VA_ARGS__)
-/*
- * Structure of a DEC/Intel/Xerox or 802.3 Ethernet header.
+#define ERROR(fmt, ...) fr_perror("radsniff: " fmt, ## __VA_ARGS__)
+
+#define RIDEBUG_ENABLED() (conf->print_packet && (fr_debug_flag > 0))
+#define RDEBUG_ENABLED() (conf->print_packet && (fr_debug_flag > 1))
+#define RDEBUG_ENABLED2() (conf->print_packet && (fr_debug_flag > 2))
+
+#define REDEBUG(fmt, ...) if (conf->print_packet) fr_perror("%s (%" PRIu64 ") " fmt , timestr, count, ## __VA_ARGS__)
+#define RIDEBUG(fmt, ...) if (conf->print_packet && (fr_debug_flag > 0)) fprintf(fr_log_fp , "%s (%" PRIu64 ") " fmt "\n", timestr, count, ## __VA_ARGS__)
+#define RDEBUG(fmt, ...) if (conf->print_packet && (fr_debug_flag > 1)) fprintf(fr_log_fp , "%s (%" PRIu64 ") " fmt "\n", timestr, count, ## __VA_ARGS__)
+#define RDEBUG2(fmt, ...) if (conf->print_packet && (fr_debug_flag > 2)) fprintf(fr_log_fp , "%s (%" PRIu64 ") " fmt "\n", timestr, count, ## __VA_ARGS__)
+
+typedef enum {
+ RS_NORMAL = 0x01,
+ RS_UNLINKED = 0x02,
+ RS_RTX = 0x04,
+ RS_REUSED = 0x08,
+ RS_ERROR = 0x10,
+ RS_LOST = 0x20
+} rs_status_t;
+
+typedef void (*rs_packet_logger_t)(uint64_t count, rs_status_t status, fr_pcap_t *handle, RADIUS_PACKET *packet,
+ struct timeval *elapsed, struct timeval *latency, bool response, bool body);
+typedef enum {
+#ifdef HAVE_COLLECTDC_H
+ RS_STATS_OUT_COLLECTD = 1,
+#endif
+ RS_STATS_OUT_STDIO
+} stats_out_t;
+
+typedef struct rs rs_t;
+
+#ifdef HAVE_COLLECTDC_H
+typedef struct rs_stats_tmpl rs_stats_tmpl_t;
+typedef struct rs_stats_value_tmpl rs_stats_value_tmpl_t;
+#endif
+
+typedef struct rs_counters {
+ uint64_t type[PW_CODE_MAX];
+} rs_counters_t;
+
+/** Stats for a single interval
+ *
+ * And interval is defined as the time between a call to the stats output function.
*/
-struct ethernet_header {
- uint8_t ethernet_dhost[ETHER_ADDR_LEN];
- uint8_t ethernet_shost[ETHER_ADDR_LEN];
- uint16_t ethernet_type;
-};
+typedef struct rs_latency {
+ int intervals; //!< Number of stats intervals.
-/*
- * Length of a DEC/Intel/Xerox or 802.3 Ethernet header.
- * Note that some compilers may pad "struct ether_header" to
- * a multiple of 4 *bytes, for example, so "sizeof (struct
- * ether_header)" may not give the right answer.
+ double latency_smoothed; //!< Smoothed moving average.
+ uint64_t latency_smoothed_count; //!< Number of CMA datapoints processed.
+
+ struct {
+ uint64_t received_total; //!< Total received over interval.
+ uint64_t linked_total; //!< Total request/response pairs over interval.
+ uint64_t unlinked_total; //!< Total unlinked over interval.
+ uint64_t reused_total; //!< Total reused over interval.
+ uint64_t lost_total; //!< Total packets definitely lost in this interval.
+ uint64_t rt_total[RS_RETRANSMIT_MAX + 1]; //!< Number of RTX until complete
+ //!< over interval.
+
+
+ double received; //!< Number of this type of packet we've received.
+ double linked; //!< Number of request/response pairs
+ double unlinked; //!< Response with no request.
+ double reused; //!< ID re-used too quickly.
+ double lost; //!< Never got a response to a request.
+ double rt[RS_RETRANSMIT_MAX + 1]; //!< Number of times we saw the same
+ //!< request packet.
+
+ long double latency_total; //!< Total latency between requests/responses in the
+ //!< interval.
+ double latency_average; //!< Average latency (this iteration).
+
+ double latency_high; //!< Latency high water mark.
+ double latency_low; //!< Latency low water mark.
+ } interval;
+} rs_latency_t;
+
+typedef struct rs_malformed {
+ uint64_t min_length_packet;
+ uint64_t min_length_field;
+ uint64_t min_length_mimatch;
+ uint64_t header_overflow;
+ uint64_t invalid_attribute;
+ uint64_t attribute_too_short;
+ uint64_t attribute_overflow;
+ uint64_t ma_invalid_length;
+ uint64_t attribute_underflow;
+ uint64_t too_many_attributes;
+ uint64_t ma_missing;
+} rs_malformed_t;
+
+/** One set of statistics
+ *
*/
-#define ETHER_HDRLEN 14
+typedef struct rs_stats {
+ int intervals; //!< Number of stats intervals.
-/*
- * Structure of an internet header, naked of options.
+ rs_latency_t exchange[PW_CODE_MAX]; //!< We end up allocating ~16K, but memory is cheap so
+ //!< what the hell. This is required because instances of
+ //!< FreeRADIUS delay Access-Rejects, which would artificially
+ //!< increase latency stats for Access-Requests.
+
+ struct timeval quiet; //!< We may need to 'mute' the stats if libpcap starts
+ //!< dropping packets, or we run out of memory.
+} rs_stats_t;
+
+/** Wrapper for RADIUS_PACKET
+ *
+ * Allows an event to be associated with a request packet. This is required because we need to disarm
+ * the event timer when a response is received, so we don't erroneously log the response as lost.
+ */
+typedef struct rs_request {
+ uint64_t id; //!< Monotonically increasing packet counter.
+ fr_event_t *event; //!< Event created when we received the original request.
+
+ struct timeval when; //!< Time when the packet was received, or next time an event
+ //!< is scheduled.
+ fr_pcap_t *in; //!< PCAP handle the original request was received on.
+ RADIUS_PACKET *packet; //!< The original packet.
+ RADIUS_PACKET *expect; //!< Request/response.
+ RADIUS_PACKET *linked; //!< The subsequent response or forwarded request the packet
+ //!< was linked against.
+
+ uint64_t rt_req; //!< Number of times we saw the same request packet.
+ uint64_t rt_rsp; //!< Number of times we saw a retransmitted response
+ //!< packet.
+ rs_latency_t *stats_req; //!< Latency entry for the request type.
+ rs_latency_t *stats_rsp; //!< Latency entry for the request type.
+
+ bool silent_cleanup; //!< Cleanup was forced before normal expiry period,
+ //!< ignore stats about packet loss.
+
+ VALUE_PAIR *link_vps; //!< VALUE_PAIRs used to link retransmissions.
+
+ bool in_request_tree; //!< Whether the request is currently in the request tree.
+ bool in_link_tree; //!< Whether the request is currently in the linked tree.
+} rs_request_t;
+
+/** Statistic write/print event
+ *
+ */
+typedef struct rs_event {
+ fr_event_list_t *list; //!< The event list.
+
+ fr_pcap_t *in; //!< PCAP handle event occurred on.
+ fr_pcap_t *out; //!< Where to write output.
+
+ rs_stats_t *stats; //!< Where to write stats.
+} rs_event_t;
+
+/** FD data which gets passed to callbacks
+ *
+ */
+typedef struct rs_update {
+ fr_event_list_t *list; //!< List to insert new event into.
+
+ fr_pcap_t *in; //!< Linked list of PCAP handles to check for drops.
+ rs_stats_t *stats; //!< Stats to process.
+} rs_update_t;
+
+
+struct rs {
+ bool from_file; //!< Were reading pcap data from files.
+ bool from_dev; //!< Were reading pcap data from devices.
+ bool from_stdin; //!< Were reading pcap data from stdin.
+ bool to_file; //!< Were writing pcap data to files.
+ bool to_stdout; //!< Were writing pcap data to stdout.
+
+ bool daemonize; //!< Daemonize and write PID out to file.
+ char const *pidfile; //!< File to write PID to.
+
+ bool from_auto; //!< From list was auto-generated.
+ bool promiscuous; //!< Capture in promiscuous mode.
+ bool print_packet; //!< Print packet info, disabled with -W
+ bool decode_attrs; //!< Whether we should decode attributes in the request
+ //!< and response.
+ bool verify_udp_checksum; //!< Check UDP checksum in packets.
+
+ char const *radius_secret; //!< Secret to decode encrypted attributes.
+
+ char *pcap_filter; //!< PCAP filter string applied to live capture devices.
+
+ char *list_attributes; //!< Raw attribute filter string.
+ DICT_ATTR const *list_da[RS_MAX_ATTRS]; //!< Output CSV with these attribute values.
+ int list_da_num;
+
+ char *link_attributes; //!< Names of DICT_ATTRs to use for rtx.
+ DICT_ATTR const *link_da[RS_MAX_ATTRS]; //!< DICT_ATTRs to link on.
+ int link_da_num; //!< Number of rtx DICT_ATTRs.
+
+ char const *filter_request; //!< Raw request filter string.
+ char const *filter_response; //!< Raw response filter string.
+
+ VALUE_PAIR *filter_request_vps; //!< Sorted filter vps.
+ VALUE_PAIR *filter_response_vps; //!< Sorted filter vps.
+ PW_CODE filter_request_code; //!< Filter request packets by code.
+ PW_CODE filter_response_code; //!< Filter response packets by code.
+
+ rs_status_t event_flags; //!< Events we log and capture on.
+ rs_packet_logger_t logger; //!< Packet logger
+
+ int buffer_pkts; //!< Size of the ring buffer to setup for live capture.
+ uint64_t limit; //!< Maximum number of packets to capture
+
+ struct {
+ int interval; //!< Time between stats updates in seconds.
+ stats_out_t out; //!< Where to write stats.
+ int timeout; //!< Maximum length of time we wait for a response.
+
+#ifdef HAVE_COLLECTDC_H
+ char const *collectd; //!< Collectd server/port/unixsocket
+ char const *prefix; //!< Prefix collectd stats with this value.
+ lcc_connection_t *handle; //!< Collectd client handle.
+ rs_stats_tmpl_t *tmpl; //!< The stats templates we created on startup.
+#endif
+ } stats;
+};
+
+#ifdef HAVE_COLLECTDC_H
+
+/** Callback for processing stats values.
+ *
*/
-struct ip_header {
- uint8_t ip_vhl; /* header length, version */
-#define IP_V(ip) (((ip)->ip_vhl & 0xf0) >> 4)
-#define IP_HL(ip) ((ip)->ip_vhl & 0x0f)
- uint8_t ip_tos; /* type of service */
- uint16_t ip_len; /* total length */
- uint16_t ip_id; /* identification */
- uint16_t ip_off; /* fragment offset field */
-#define I_DF 0x4000 /* dont fragment flag */
-#define IP_MF 0x2000 /* more fragments flag */
-#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
- uint8_t ip_ttl; /* time to live */
- uint8_t ip_p; /* protocol */
- uint16_t ip_sum; /* checksum */
- struct in_addr ip_src,ip_dst; /* source and dest address */
+typedef void (*rs_stats_cb_t)(rs_t *conf, rs_stats_value_tmpl_t *tmpl);
+struct rs_stats_value_tmpl {
+ void *src; //!< Pointer to source field in struct. Must be set by
+ //!< stats_collectdc_init caller.
+ int type; //!< Stats type.
+ rs_stats_cb_t cb; //!< Callback used to process stats
+ void *dst; //!< Pointer to dst field in value struct. Must be set
+ //!< by stats_collectdc_init caller.
};
-/*
- * UDP protocol header.
- * Per RFC 768, September, 1981.
+/** Stats templates
+ *
+ * This gets processed to turn radsniff stats structures into collectd lcc_value_list_t structures.
*/
-struct udp_header {
- uint16_t udp_sport; /* source port */
- uint16_t udp_dport; /* destination port */
- uint16_t udp_ulen; /* udp length */
- uint16_t udp_sum; /* udp checksum */
+struct rs_stats_tmpl
+{
+ rs_stats_value_tmpl_t *value_tmpl; //!< Value template
+ void *stats; //!< Struct containing the raw stats to process
+ lcc_value_list_t *value; //!< Collectd stats struct to populate
+
+ rs_stats_tmpl_t *next; //!< Next...
};
/*
- * RADIUS packet length.
- * RFC 2865, Section 3., subsection 'length' says:
- * " ... and maximum length is 4096."
+ * collectd.c - Registration and processing functions
*/
-#define MAX_RADIUS_LEN 4096
-#define MIN_RADIUS_LEN 20
-#define SNAPLEN (sizeof(struct ethernet_header) + sizeof(struct ip_header) + sizeof(struct udp_header) + MAX_RADIUS_LEN)
-
-typedef struct radius_packet_t {
- uint8_t code;
- uint8_t id;
- uint8_t length[2];
- uint8_t vector[AUTH_VECTOR_LEN];
- uint8_t data[1];
-} radius_packet_t;
-
-#define AUTH_HDR_LEN 20
+rs_stats_tmpl_t *rs_stats_collectd_init_latency(TALLOC_CTX *ctx, rs_stats_tmpl_t **out, rs_t *conf,
+ char const *type, rs_latency_t *stats, PW_CODE code);
+void rs_stats_collectd_do_stats(rs_t *conf, rs_stats_tmpl_t *tmpls, struct timeval *now);
+int rs_stats_collectd_open(rs_t *conf);
+int rs_stats_collectd_close(rs_t *conf);
+
+#endif
extern "C" {
#endif
-#define HOME_TYPE_INVALID (0)
-#define HOME_TYPE_AUTH (1)
-#define HOME_TYPE_ACCT (2)
+typedef enum {
+ HOME_TYPE_INVALID = 0,
+ HOME_TYPE_AUTH,
+ HOME_TYPE_ACCT
#ifdef WITH_COA
-#define HOME_TYPE_COA (3)
+ ,HOME_TYPE_COA
#endif
+} home_type_t;
-#define HOME_PING_CHECK_NONE (0)
-#define HOME_PING_CHECK_STATUS_SERVER (1)
-#define HOME_PING_CHECK_REQUEST (2)
+typedef enum {
+ HOME_PING_CHECK_NONE = 0,
+ HOME_PING_CHECK_STATUS_SERVER,
+ HOME_PING_CHECK_REQUEST
+} home_ping_check_t;
-#define HOME_STATE_ALIVE (0)
-#define HOME_STATE_ZOMBIE (1)
-#define HOME_STATE_IS_DEAD (2)
-#define HOME_STATE_UNKNOWN (3)
+typedef enum {
+ HOME_STATE_ALIVE = 0,
+ HOME_STATE_ZOMBIE,
+ HOME_STATE_IS_DEAD,
+ HOME_STATE_UNKNOWN
+} home_state_t;
typedef struct fr_socket_limit_t {
- int max_connections;
- int num_connections;
- int max_requests;
- int num_requests;
- int lifetime;
- int idle_timeout;
+ uint32_t max_connections;
+ uint32_t num_connections;
+ uint32_t max_requests;
+ uint32_t num_requests;
+ uint32_t lifetime;
+ uint32_t idle_timeout;
} fr_socket_limit_t;
typedef struct home_server {
fr_ipaddr_t ipaddr;
- int port;
+ uint16_t port;
int type; /* auth/acct */
int proto;
fr_event_t *ev;
struct timeval when;
- int response_window;
- int max_outstanding; /* don't overload it */
- int currently_outstanding;
+ struct timeval response_window;
+ uint32_t max_outstanding; /* don't overload it */
+ uint32_t currently_outstanding;
time_t last_packet_sent;
time_t last_packet_recv;
+ time_t last_failed_open;
struct timeval revive_time;
struct timeval zombie_period_start;
- int zombie_period; /* unresponsive for T, mark it dead */
+ uint32_t zombie_period; /* unresponsive for T, mark it dead */
int state;
char const *ping_user_name;
char const *ping_user_password;
- int ping_interval;
- int num_pings_to_alive;
- int num_sent_pings;
- int num_received_pings;
- int ping_timeout;
+ uint32_t ping_interval;
+ uint32_t num_pings_to_alive;
+ uint32_t num_sent_pings;
+ uint32_t num_received_pings;
+ uint32_t ping_timeout;
- int revive_interval; /* if it doesn't support pings */
+ uint32_t revive_interval; /* if it doesn't support pings */
CONF_SECTION *cs;
#ifdef WITH_COA
- int coa_irt;
- int coa_mrc;
- int coa_mrt;
- int coa_mrd;
+ uint32_t coa_irt;
+ uint32_t coa_mrc;
+ uint32_t coa_mrt;
+ uint32_t coa_mrd;
#endif
#ifdef WITH_TLS
fr_tls_server_conf_t *tls;
fr_stats_ema_t ema;
#endif
-} home_server;
+} home_server_t;
typedef enum home_pool_type_t {
char const *virtual_server; /* for pre/post-proxy */
- home_server *fallback;
+ home_server_t *fallback;
int in_fallback;
time_t time_all_dead;
int num_home_servers;
- home_server *servers[1];
+ home_server_t *servers[1];
} home_pool_t;
void realms_free(void);
REALM *realm_find(char const *name); /* name is from a packet */
REALM *realm_find2(char const *name); /* ... with name taken from realm_find */
- int realms_home_server_add(home_server *home, CONF_SECTION *cs, int dual);
+ int realms_home_server_add(home_server_t *home, CONF_SECTION *cs, int dual);
int realms_pool_add(home_pool_t *pool, CONF_SECTION *cs);
int realms_realm_add( REALM *r, CONF_SECTION *cs);
-void home_server_update_request(home_server *home, REQUEST *request);
-home_server *home_server_ldb(char const *realmname, home_pool_t *pool, REQUEST *request);
-home_server *home_server_find(fr_ipaddr_t *ipaddr, int port, int proto);
+void home_server_update_request(home_server_t *home, REQUEST *request);
+home_server_t *home_server_ldb(char const *realmname, home_pool_t *pool, REQUEST *request);
+home_server_t *home_server_find(fr_ipaddr_t *ipaddr, uint16_t port, int proto);
#ifdef WITH_COA
-home_server *home_server_byname(char const *name, int type);
+home_server_t *home_server_byname(char const *name, int type);
#endif
#ifdef WITH_STATS
-home_server *home_server_bynumber(int number);
+home_server_t *home_server_bynumber(int number);
#endif
home_pool_t *home_pool_byname(char const *name, int type);
extern "C" {
#endif
-int soh_verify(REQUEST *request, uint8_t const *data, unsigned int data_len);
+int soh_verify(REQUEST *request, uint8_t const *data, unsigned int data_len) CC_HINT(nonnull);
uint16_t soh_pull_be_16(uint8_t const *p);
uint32_t soh_pull_be_24(uint8_t const *p);
uint32_t soh_pull_be_32(uint8_t const *p);
#ifdef WITH_STATS
typedef struct fr_stats_t {
- fr_uint_t total_requests;
- fr_uint_t total_invalid_requests;
- fr_uint_t total_dup_requests;
- fr_uint_t total_responses;
- fr_uint_t total_access_accepts;
- fr_uint_t total_access_rejects;
- fr_uint_t total_access_challenges;
- fr_uint_t total_malformed_requests;
- fr_uint_t total_bad_authenticators;
- fr_uint_t total_packets_dropped;
- fr_uint_t total_no_records;
- fr_uint_t total_unknown_types;
- fr_uint_t total_timeouts;
- time_t last_packet;
- fr_uint_t elapsed[8];
+ fr_uint_t total_requests;
+ fr_uint_t total_invalid_requests;
+ fr_uint_t total_dup_requests;
+ fr_uint_t total_responses;
+ fr_uint_t total_access_accepts;
+ fr_uint_t total_access_rejects;
+ fr_uint_t total_access_challenges;
+ fr_uint_t total_malformed_requests;
+ fr_uint_t total_bad_authenticators;
+ fr_uint_t total_packets_dropped;
+ fr_uint_t total_no_records;
+ fr_uint_t total_unknown_types;
+ fr_uint_t total_timeouts;
+ time_t last_packet;
+ fr_uint_t elapsed[8];
} fr_stats_t;
typedef struct fr_stats_ema_t {
- int window;
-
- int f1, f10;
- int ema1, ema10;
+ uint32_t window;
+ uint32_t f1, f10;
+ uint32_t ema1, ema10;
} fr_stats_ema_t;
extern fr_stats_t radius_auth_stats;
* If we have BOTH utmp.h and utmpx.h, then
* we prefer to use utmp.h, but only on systems other than Solaris.
*/
-#if !defined(sun) && !defined(sgi) && !defined(hpux)
-#ifdef HAVE_UTMP_H
-#undef HAVE_UTMPX_H
-#endif
+#if !defined(__sun) && !defined(sgi) && !defined(hpux)
+# ifdef HAVE_UTMP_H
+# undef HAVE_UTMPX_H
+# endif
#endif
#if defined(HAVE_UTMP_H) || defined(HAVE_UTMPX_H)
RCSIDH(tcp_h, "$Id$")
-int fr_tcp_socket(fr_ipaddr_t *ipaddr, int port);
-int fr_tcp_client_socket(fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr, int dst_port);
+int fr_tcp_client_socket(fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port);
int fr_tcp_read_packet(RADIUS_PACKET *packet, int flags);
RADIUS_PACKET *fr_tcp_recv(int sockfd, int flags);
-RADIUS_PACKET *fr_tcp_accept(int sockfd);
-ssize_t fr_tcp_write_packet(RADIUS_PACKET *packet);
#endif /* FR_TCP_H */
(void) pthread_once(&__fr_thread_local_once_##_n, __fr_thread_local_key_init_##_n);\
return pthread_getspecific(__fr_thread_local_key_##_n);\
}\
+DIAG_OFF(unused-function)\
static inline _t __fr_thread_local_get_##_n(void)\
{\
return pthread_getspecific(__fr_thread_local_key_##_n);\
}\
+DIAG_ON(unused-function)\
static inline int __fr_thread_local_set_##_n(_t val)\
{\
return pthread_setspecific(__fr_thread_local_key_##_n, val);\
unsigned int (*record_minus)(record_t *buf, void *ptr,
unsigned int size);
+ bool invalid_hb_used;
/*
* Framed-MTU attribute in RADIUS,
/* TLS */
void tls_global_init(void);
+int tls_global_version_check(char const *acknowledged);
+void tls_global_cleanup(void);
tls_session_t *tls_new_session(fr_tls_server_conf_t *conf, REQUEST *request,
int client_cert);
tls_session_t *tls_new_client_session(fr_tls_server_conf_t *conf, int fd);
void session_close(tls_session_t *ssn);
void session_init(tls_session_t *ssn);
-#define FR_TLS_EX_INDEX_HANDLER (0)
-#define FR_TLS_EX_INDEX_CONF (1)
-#define FR_TLS_EX_INDEX_REQUEST (2)
-#define FR_TLS_EX_INDEX_CERTS (3)
-#define FR_TLS_EX_INDEX_IDENTITY (4)
-#define FR_TLS_EX_INDEX_STORE (6)
-#define FR_TLS_EX_INDEX_SSN (7)
+#define FR_TLS_EX_INDEX_HANDLER (10)
+#define FR_TLS_EX_INDEX_CONF (11)
+#define FR_TLS_EX_INDEX_REQUEST (12)
+#define FR_TLS_EX_INDEX_IDENTITY (13)
+#define FR_TLS_EX_INDEX_STORE (14)
+#define FR_TLS_EX_INDEX_SSN (15)
+#define FR_TLS_EX_INDEX_TALLOC (16)
+
+extern int FR_TLS_EX_INDEX_CERTS;
/* configured values goes right here */
struct fr_tls_server_conf_t {
SSL_CTX *ctx;
CONF_SECTION *cs;
- char *private_key_password;
- char *private_key_file;
- char *certificate_file;
- char *random_file;
- char *ca_path;
- char *ca_file;
- char *dh_file;
- char *rsa_file;
+ char const *private_key_password;
+ char const *private_key_file;
+ char const *certificate_file;
+ char const *random_file;
+ char const *ca_path;
+ char const *ca_file;
+ char const *dh_file;
+ char const *rsa_file;
bool rsa_key;
bool dh_key;
- int rsa_key_length;
- int dh_key_length;
- int verify_depth;
+ uint32_t rsa_key_length;
+ uint32_t dh_key_length;
+ uint32_t verify_depth;
bool file_type;
bool include_length;
/*
* Always < 4096 (due to radius limit), 0 by default = 2048
*/
- int fragment_size;
+ uint32_t fragment_size;
bool check_crl;
bool allow_expired_crl;
- char *check_cert_cn;
- char *cipher_list;
- char *check_cert_issuer;
+ char const *check_cert_cn;
+ char const *cipher_list;
+ char const *check_cert_issuer;
bool session_cache_enable;
- int session_timeout;
- int session_cache_size;
- char *session_id_name;
- char *session_cache_path;
+ uint32_t session_timeout;
+ uint32_t session_cache_size;
+ char const *session_id_name;
+ char const *session_cache_path;
char session_context_id[SSL_MAX_SSL_SESSION_ID_LENGTH];
time_t session_last_flushed;
- char *verify_tmp_dir;
- char *verify_client_cert_cmd;
+ char const *verify_tmp_dir;
+ char const *verify_client_cert_cmd;
bool require_client_cert;
#ifdef HAVE_OPENSSL_OCSP_H
*/
bool ocsp_enable;
bool ocsp_override_url;
- char *ocsp_url;
+ char const *ocsp_url;
bool ocsp_use_nonce;
X509_STORE *ocsp_store;
- int ocsp_timeout;
+ uint32_t ocsp_timeout;
bool ocsp_softfail;
#endif
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
#ifndef OPENSSL_NO_ECDH
- char *ecdh_curve;
+ char const *ecdh_curve;
#endif
#endif
#ifdef PSK_MAX_IDENTITY_LEN
- char *psk_identity;
- char *psk_password;
+ char const *psk_identity;
+ char const *psk_password;
#endif
};
T_OP_REG_EQ, /* =~ */
T_OP_REG_NE, /* !~ */
T_OP_CMP_TRUE, /* =* 20 */
- T_OP_CMP_FALSE, /* !* */
+ T_OP_CMP_FALSE, /* !* */
T_OP_CMP_EQ, /* == */
T_HASH, /* # */
T_BARE_WORD, /* bare word */
char const *def);
-int getword (char const **ptr, char *buf, int buflen);
-int getbareword (char const **ptr, char *buf, int buflen);
-FR_TOKEN gettoken(char const **ptr, char *buf, int buflen);
-FR_TOKEN getstring(char const **ptr, char *buf, int buflen);
+int getword (char const **ptr, char *buf, int buflen, bool unescape);
+FR_TOKEN gettoken(char const **ptr, char *buf, int buflen, bool unescape);
+FR_TOKEN getstring(char const **ptr, char *buf, int buflen, bool unescape);
char const *fr_token_name(int);
#ifdef __cplusplus
END OF TERMS AND CONDITIONS
\f
- How to Apply These Terms to Your New Libraries
+ How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
#
TARGET := libfreeradius-radius.a
-SOURCES := 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 \
- heap.c tcp.c base64.c
+SOURCES := cbuff.c cursor.c debug.c dict.c filters.c hash.c hmac.c hmacsha1.c \
+ isaac.c log.c misc.c missing.c md4.c md5.c pcap.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 heap.c tcp.c base64.c version.c
SRC_CFLAGS := -D_LIBRADIUS -I$(top_builddir)/src
# System libraries discovered by our top level configure script, links things
# like pthread and the regexp libraries.
-TGT_LDLIBS := $(LIBS)
+TGT_LDLIBS := $(LIBS) $(PCAP_LIBS)
+TGT_LDFLAGS := $(LDFLAGS) $(PCAP_LDFLAGS)
#include <freeradius-devel/libradius.h>
#include <freeradius-devel/base64.h>
-/* Get UCHAR_MAX from stdint.h, in src/include/missing.h */
-#include <limits.h>
-
#define us(x) (uint8_t) x
/** Base 64 encode binary data
*
* Base64 encode IN array of size INLEN into OUT array of size OUTLEN.
*
- * @param[in] in Data to encode.
- * @param[in] inlen Length of data to encode.
* @param[out] out Where to write Base64 string.
* @param[in] outlen size of buffer including NULL byte.
+ * @param[in] in Data to encode.
+ * @param[in] inlen Length of data to encode.
* @return The amount of data we wrote to the buffer or -1 if output buffer
* was too small.
*/
-size_t fr_base64_encode(uint8_t const *in, size_t inlen, char *out, size_t outlen)
+size_t fr_base64_encode(char *out, size_t outlen, uint8_t const *in, size_t inlen)
{
static char const b64str[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklm"
"nopqrstuvwxyz0123456789+/";
* This means that, when applicable, you must remove any line terminators
* that is part of the data stream before calling this function.
*
- * @param[in] in Base64 string to decode.
- * @param[in] inlen length of Base64 string.
* @param[out] out Where to write the decoded data.
* @param[in] outlen The length of the output buffer.
+ * @param[in] in Base64 string to decode.
+ * @param[in] inlen length of Base64 string.
* @return -1 on error, else the length of decoded data.
*/
-ssize_t fr_base64_decode(char const *in, size_t inlen, uint8_t *out,
- size_t outlen)
+ssize_t fr_base64_decode(uint8_t *out, size_t outlen, char const *in, size_t inlen)
{
uint8_t *p = out;
if (in[3] == '=') {
if (inlen != 4) break;
} else {
- if (!fr_isbase64(in[3])) break;
+ if (!fr_isbase64(in[3])) break;
*p++ = ((b64[us(in[2])] << 6) & 0xc0) | b64[us(in[3])];
- }
+ }
}
in += 4;
inlen -= 4;
- }
+ }
if (inlen != 0) {
return -1;
}
- return p - out;
+ return p - out;
}
TALLOC_FREE(cbuff->elem[cbuff->in]);
}
- cbuff->elem[cbuff->in] = obj;
- talloc_steal(cbuff, obj);
+ cbuff->elem[cbuff->in] = talloc_steal(cbuff, obj);
cbuff->in = (cbuff->in + 1) & cbuff->size;
--- /dev/null
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 if the
+ * License as published by the Free Software Foundation.
+ *
+ * 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
+ */
+
+/**
+ * $Id$
+ * @file cursor.c
+ * @brief Functions to iterate over collections of VALUE_PAIRs
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2013 The FreeRADIUS Server Project.
+ */
+
+#include <freeradius-devel/libradius.h>
+
+/** Setup a cursor to iterate over attribute pairs
+ *
+ * @param cursor Where to initialise the cursor (uses existing structure).
+ * @param node to start from.
+ */
+VALUE_PAIR *_fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR const * const *node)
+{
+ memset(cursor, 0, sizeof(*cursor));
+
+ if (!node || !cursor) {
+ return NULL;
+ }
+
+ /*
+ * Useful check to see if uninitialised memory is pointed
+ * to by node
+ */
+#ifndef NDEBUG
+ if (*node) VERIFY_VP(*node);
+#endif
+ memcpy(&cursor->first, &node, sizeof(cursor->first));
+ cursor->current = *cursor->first;
+
+ if (cursor->current) {
+ VERIFY_VP(cursor->current);
+ cursor->next = cursor->current->next;
+ }
+
+ return cursor->current;
+}
+
+void fr_cursor_copy(vp_cursor_t *out, vp_cursor_t *in)
+{
+ memcpy(out, in, sizeof(*out));
+}
+
+VALUE_PAIR *fr_cursor_first(vp_cursor_t *cursor)
+{
+ cursor->current = *cursor->first;
+
+ if (cursor->current) {
+ VERIFY_VP(cursor->current);
+ cursor->next = cursor->current->next;
+ if (cursor->next) VERIFY_VP(cursor->next);
+ cursor->found = NULL;
+ }
+
+ return cursor->current;
+}
+
+/** Return the last pair in the list
+ *
+ */
+VALUE_PAIR *fr_cursor_last(vp_cursor_t *cursor)
+{
+ if (!*cursor->first) return NULL;
+
+ /* Need to start at the start */
+ if (!cursor->current) {
+ fr_cursor_first(cursor);
+ }
+
+ /* Wind to the end */
+ while (cursor->next) {
+ fr_cursor_next(cursor);
+ }
+
+ return fr_cursor_current(cursor);
+}
+
+/** Iterate over attributes of a given type in the pairlist
+ *
+ *
+ */
+VALUE_PAIR *fr_cursor_next_by_num(vp_cursor_t *cursor, unsigned int attr, unsigned int vendor, int8_t tag)
+{
+ VALUE_PAIR *i;
+
+ i = pairfind(!cursor->found ? cursor->current : cursor->found->next, attr, vendor, tag);
+ if (!i) {
+ cursor->next = NULL;
+ cursor->current = NULL;
+
+ return NULL;
+ }
+
+ cursor->next = i->next;
+ cursor->current = i;
+ cursor->found = i;
+
+ return i;
+}
+
+/** Iterate over attributes of a given DA in the pairlist
+ *
+ *
+ */
+VALUE_PAIR *fr_cursor_next_by_da(vp_cursor_t *cursor, DICT_ATTR const *da, int8_t tag)
+{
+ VALUE_PAIR *i;
+
+ i = pairfind_da(!cursor->found ? cursor->current : cursor->found->next, da, tag);
+ if (!i) {
+ cursor->next = NULL;
+ cursor->current = NULL;
+
+ return NULL;
+ }
+
+ cursor->next = i->next;
+ cursor->current = i;
+ cursor->found = i;
+
+ return i;
+}
+
+/** Retrieve the next VALUE_PAIR
+ *
+ *
+ */
+VALUE_PAIR *fr_cursor_next(vp_cursor_t *cursor)
+{
+ cursor->current = cursor->next;
+ if (cursor->current) {
+ VERIFY_VP(cursor->current);
+
+ /*
+ * Set this now in case 'current' gets freed before
+ * fr_cursor_next is called again.
+ */
+ cursor->next = cursor->current->next;
+
+ /*
+ * Next call to fr_cursor_next_by_num will start from the current
+ * position in the list, not the last found instance.
+ */
+ cursor->found = NULL;
+ }
+
+ return cursor->current;
+}
+
+VALUE_PAIR *fr_cursor_current(vp_cursor_t *cursor)
+{
+ if (cursor->current) {
+ VERIFY_VP(cursor->current);
+ }
+
+ return cursor->current;
+}
+
+/** Insert a VP
+ *
+ * @todo don't use with pairdelete
+ */
+void fr_cursor_insert(vp_cursor_t *cursor, VALUE_PAIR *add)
+{
+ VALUE_PAIR *i;
+
+ if (!add) {
+ return;
+ }
+
+ VERIFY_VP(add);
+
+ /*
+ * Cursor was initialised with a pointer to a NULL value_pair
+ */
+ if (!*cursor->first) {
+ *cursor->first = add;
+ cursor->current = add;
+
+ return;
+ }
+
+ /*
+ * We don't yet know where the last VALUE_PAIR is
+ *
+ * Assume current is closer to the end of the list and use that if available.
+ */
+ if (!cursor->last) {
+ cursor->last = cursor->current ? cursor->current : *cursor->first;
+ }
+
+ VERIFY_VP(cursor->last);
+
+ /*
+ * Something outside of the cursor added another VALUE_PAIR
+ */
+ if (cursor->last->next) {
+ for (i = cursor->last; i; i = i->next) {
+ VERIFY_VP(i);
+ cursor->last = i;
+ }
+ }
+
+ /*
+ * Either current was never set, or something iterated to the end of the
+ * attribute list.
+ */
+ if (!cursor->current) {
+ cursor->current = add;
+ }
+
+ /*
+ * If there's no next cursor, and the pair we just inserted has additional
+ * linked pairs, we need to set next to be the next VP in the list.
+ */
+ if (!cursor->next) {
+ cursor->next = add->next;
+ }
+
+ cursor->last->next = add;
+}
+
+/** Remove the current pair
+ *
+ * @todo this is really inefficient and should be fixed...
+ *
+ * @param cursor to remove the current pair from.
+ * @return NULL on error, else the VALUE_PAIR we just removed.
+ */
+VALUE_PAIR *fr_cursor_remove(vp_cursor_t *cursor)
+{
+ VALUE_PAIR *vp, **last;
+
+ vp = fr_cursor_current(cursor);
+ if (!vp) {
+ return NULL;
+ }
+
+ last = cursor->first;
+ while (*last != vp) {
+ last = &(*last)->next;
+ }
+
+ fr_cursor_next(cursor); /* Advance the cursor past the one were about to delete */
+
+ *last = vp->next;
+ vp->next = NULL;
+
+ /* Fixup cursor->found if we removed the VP it was referring to */
+ if (vp == cursor->found) cursor->found = *last;
+
+ return vp;
+}
+
+/** Replace the current pair
+ *
+ * @todo this is really inefficient and should be fixed...
+ *
+ * @param cursor to replace the current pair in.
+ * @param new VALUE_PAIR to insert.
+ * @return NULL on error, else the VALUE_PAIR we just replaced.
+ */
+VALUE_PAIR *fr_cursor_replace(vp_cursor_t *cursor, VALUE_PAIR *new)
+{
+ VALUE_PAIR *vp, **last;
+
+ vp = fr_cursor_current(cursor);
+ if (!vp) {
+ *cursor->first = new;
+ return NULL;
+ }
+
+ last = cursor->first;
+ while (*last != vp) {
+ last = &(*last)->next;
+ }
+
+ fr_cursor_next(cursor); /* Advance the cursor past the one were about to replace */
+
+ *last = new;
+ new->next = vp->next;
+ vp->next = NULL;
+
+ return vp;
+}
--- /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 <assert.h>
+#include <freeradius-devel/libradius.h>
+#include <sys/stat.h>
+
+#if defined(HAVE_MALLOPT) && defined(HAVE_MALLOC_H)
+# include <malloc.h>
+#endif
+
+/*
+ * runtime backtrace functions are not POSIX but are included in
+ * glibc, OSX >= 10.5 and various BSDs
+ */
+#ifdef HAVE_EXECINFO
+# include <execinfo.h>
+#endif
+
+#ifdef HAVE_SYS_PRCTL_H
+# include <sys/prctl.h>
+#endif
+
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif
+
+#ifdef HAVE_PTHREAD_H
+# define PTHREAD_MUTEX_LOCK pthread_mutex_lock
+# define PTHREAD_MUTEX_UNLOCK pthread_mutex_unlock
+#else
+# define PTHREAD_MUTEX_LOCK(_x)
+# define PTHREAD_MUTEX_UNLOCK(_x)
+#endif
+
+#ifdef HAVE_EXECINFO
+# define MAX_BT_FRAMES 128
+# define MAX_BT_CBUFF 65536 //!< Should be a power of 2
+
+# ifdef HAVE_PTHREAD_H
+static pthread_mutex_t fr_debug_init = PTHREAD_MUTEX_INITIALIZER;
+# endif
+
+typedef struct fr_bt_info {
+ void *obj; //!< Memory address of the block of allocated memory.
+ void *frames[MAX_BT_FRAMES]; //!< Backtrace frame data
+ int count; //!< Number of frames stored
+} fr_bt_info_t;
+
+struct fr_bt_marker {
+ void *obj; //!< Pointer to the parent object, this is our needle
+ //!< when we iterate over the contents of the circular buffer.
+ fr_cbuff_t *cbuff; //!< Where we temporarily store the backtraces
+};
+#endif
+
+static char panic_action[512]; //!< The command to execute when panicking.
+static fr_fault_cb_t panic_cb = NULL; //!< Callback to execute whilst panicking, before the
+ //!< panic_action.
+static fr_fault_log_t fr_fault_log = NULL; //!< Function to use to process logging output.
+static int fr_fault_log_fd = STDERR_FILENO; //!< Where to write debug output.
+
+static int fr_debugger_present = -1; //!< Whether were attached to by a debugger.
+
+#ifdef HAVE_SYS_RESOURCE_H
+static struct rlimit core_limits;
+#endif
+
+#define FR_FAULT_LOG(fmt, ...) fr_fault_log(fmt "\n", ## __VA_ARGS__)
+
+/** Stub callback to see if the SIGTRAP handler is overriden
+ *
+ * @param signum signal raised.
+ */
+static void _sigtrap_handler(UNUSED int signum)
+{
+ fr_debugger_present = 0;
+ signal(SIGTRAP, SIG_DFL);
+}
+
+/** Break in debugger (if were running under a debugger)
+ *
+ * If the server is running under a debugger this will raise a
+ * SIGTRAP which will pause the running process.
+ *
+ * If the server is not running under debugger then this will do nothing.
+ */
+void fr_debug_break(void)
+{
+ if (fr_debugger_present == -1) {
+ fr_debugger_present = 0;
+ signal(SIGTRAP, _sigtrap_handler);
+ raise(SIGTRAP);
+ } else if (fr_debugger_present == 1) {
+ raise(SIGTRAP);
+ }
+}
+
+#ifdef HAVE_EXECINFO
+/** Generate a backtrace for an object during destruction
+ *
+ * If this is the first entry being inserted
+ */
+static int _fr_do_bt(fr_bt_marker_t *marker)
+{
+ fr_bt_info_t *bt;
+
+ if (!fr_assert(marker->obj) || !fr_assert(marker->cbuff)) {
+ return -1;
+ }
+
+ bt = talloc_zero(marker->cbuff, fr_bt_info_t);
+ if (!bt) {
+ return -1;
+ }
+ bt->count = backtrace(bt->frames, MAX_BT_FRAMES);
+ fr_cbuff_rp_insert(marker->cbuff, bt);
+
+ return 0;
+}
+
+/** Print backtrace entry for a given object
+ *
+ * @param cbuff to search in.
+ * @param obj pointer to original object
+ */
+void backtrace_print(fr_cbuff_t *cbuff, void *obj)
+{
+ fr_bt_info_t *p;
+ bool found = false;
+ int i = 0;
+ char **frames;
+
+ while ((p = fr_cbuff_rp_next(cbuff, NULL))) {
+ if ((p == obj) || !obj) {
+ found = true;
+ frames = backtrace_symbols(p->frames, p->count);
+
+ fprintf(stderr, "Stacktrace for: %p\n", p);
+ for (i = 0; i < p->count; i++) {
+ fprintf(stderr, "%s\n", frames[i]);
+ }
+
+ /* We were only asked to look for one */
+ if (obj) {
+ return;
+ }
+ }
+ };
+
+ if (!found) {
+ fprintf(stderr, "No backtrace available for %p", obj);
+ }
+}
+
+/** Inserts a backtrace marker into the provided context
+ *
+ * Allows for maximum laziness and will initialise a circular buffer if one has not already been created.
+ *
+ * Code augmentation should look something like:
+@verbatim
+ // Create a static cbuffer pointer, the first call to backtrace_attach will initialise it
+ static fr_cbuff *my_obj_bt;
+
+ my_obj_t *alloc_my_obj(TALLOC_CTX *ctx) {
+ my_obj_t *this;
+
+ this = talloc(ctx, my_obj_t);
+
+ // Attach backtrace marker to object
+ backtrace_attach(&my_obj_bt, this);
+
+ return this;
+ }
+@endverbatim
+ *
+ * Then, later when a double free occurs:
+@verbatim
+ (gdb) call backtrace_print(&my_obj_bt, <pointer to double freed memory>)
+@endverbatim
+ *
+ * which should print a limited backtrace to stderr. Note, this backtrace will not include any argument
+ * values, but should at least show the code path taken.
+ *
+ * @param cbuff this should be a pointer to a static *fr_cbuff.
+ * @param obj we want to generate a backtrace for.
+ */
+fr_bt_marker_t *fr_backtrace_attach(fr_cbuff_t **cbuff, TALLOC_CTX *obj)
+{
+ fr_bt_marker_t *marker;
+
+ if (*cbuff == NULL) {
+ PTHREAD_MUTEX_LOCK(&fr_debug_init);
+ /* Check again now we hold the mutex - eww*/
+ if (*cbuff == NULL) {
+ TALLOC_CTX *ctx;
+
+ ctx = fr_autofree_ctx();
+ *cbuff = fr_cbuff_alloc(ctx, MAX_BT_CBUFF, true);
+ }
+ PTHREAD_MUTEX_UNLOCK(&fr_debug_init);
+ }
+
+ marker = talloc(obj, fr_bt_marker_t);
+ if (!marker) {
+ return NULL;
+ }
+
+ marker->obj = (void *) obj;
+ marker->cbuff = *cbuff;
+
+ talloc_set_destructor(marker, _fr_do_bt);
+
+ return marker;
+}
+#else
+void backtrace_print(UNUSED fr_cbuff_t *cbuff, UNUSED void *obj)
+{
+ fprintf(stderr, "Server built without fr_backtrace_* support, requires execinfo.h and possibly -lexecinfo\n");
+}
+fr_bt_marker_t *fr_backtrace_attach(UNUSED fr_cbuff_t **cbuff, UNUSED TALLOC_CTX *obj)
+{
+ fprintf(stderr, "Server built without fr_backtrace_* support, requires execinfo.h and possibly -lexecinfo\n");
+ abort();
+}
+#endif /* ifdef HAVE_EXECINFO */
+
+static int _panic_on_free(UNUSED char *foo)
+{
+ fr_fault(SIGUSR1);
+ return -1; /* this should make the free fail */
+}
+
+/** Insert memory into the context of another talloc memory chunk which
+ * causes a panic when freed.
+ *
+ * @param ctx TALLOC_CTX to monitor for frees.
+ */
+void fr_panic_on_free(TALLOC_CTX *ctx)
+{
+ char *ptr;
+
+ ptr = talloc(ctx, char);
+ talloc_set_destructor(ptr, _panic_on_free);
+}
+
+/** Set the dumpable flag, also controls whether processes can PATTACH
+ *
+ * @param dumpable whether we should allow core dumping
+ */
+#if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE)
+static int fr_set_dumpable_flag(bool dumpable)
+{
+ if (prctl(PR_SET_DUMPABLE, dumpable ? 1 : 0) < 0) {
+ fr_strerror_printf("Cannot re-enable core dumps: prctl(PR_SET_DUMPABLE) failed: %s",
+ fr_syserror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+#else
+static int fr_set_dumpable_flag(UNUSED bool dumpable)
+{
+ fr_strerror_printf("Changing value of PR_DUMPABLE not supported on this system");
+ return -2;
+}
+#endif
+
+/** Get the processes dumpable flag
+ *
+ */
+#if defined(HAVE_SYS_PRCTL_H) && defined(PR_GET_DUMPABLE)
+static int fr_get_dumpable_flag(void)
+{
+ int ret;
+
+ ret = prctl(PR_GET_DUMPABLE);
+ if (ret < 0) {
+ fr_strerror_printf("Cannot get dumpable flag: %s", fr_syserror(errno));
+ return -1;
+ }
+
+ /*
+ * Linux is crazy and prctl sometimes returns 2 for disabled
+ */
+ if (ret != 1) return 0;
+ return 1;
+}
+#else
+static int fr_get_dumpable_flag(void)
+{
+ fr_strerror_printf("Getting value of PR_DUMPABLE not supported on this system");
+ return -2;
+}
+#endif
+
+
+/** Get the current maximum for core files
+ *
+ * Do this before anything else so as to ensure it's properly initialized.
+ */
+int fr_set_dumpable_init(void)
+{
+#ifdef HAVE_SYS_RESOURCE_H
+ if (getrlimit(RLIMIT_CORE, &core_limits) < 0) {
+ fr_strerror_printf("Failed to get current core limit: %s", fr_syserror(errno));
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+/** Enable or disable core dumps
+ *
+ * @param allow_core_dumps whether to enable or disable core dumps.
+ */
+int fr_set_dumpable(bool allow_core_dumps)
+{
+ /*
+ * If configured, turn core dumps off.
+ */
+ if (!allow_core_dumps) {
+#ifdef HAVE_SYS_RESOURCE_H
+ struct rlimit no_core;
+
+ no_core.rlim_cur = 0;
+ no_core.rlim_max = 0;
+
+ if (setrlimit(RLIMIT_CORE, &no_core) < 0) {
+ fr_strerror_printf("Failed disabling core dumps: %s", fr_syserror(errno));
+
+ return -1;
+ }
+#endif
+ return 0;
+ }
+
+ if (fr_set_dumpable_flag(true) < 0) return -1;
+
+ /*
+ * Reset the core dump limits to their original value.
+ */
+#ifdef HAVE_SYS_RESOURCE_H
+ if (setrlimit(RLIMIT_CORE, &core_limits) < 0) {
+ fr_strerror_printf("Cannot update core dump limit: %s", fr_syserror(errno));
+
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+/** Check to see if panic_action file is world writeable
+ *
+ * @return 0 if file is OK, else -1.
+ */
+static int fr_fault_check_permissions(void)
+{
+ char const *p, *q;
+ size_t len;
+ char filename[256];
+ struct stat statbuf;
+
+ /*
+ * Try and guess which part of the command is the binary, and check to see if
+ * it's world writeable, to try and save the admin from their own stupidity.
+ *
+ * @fixme we should do this properly and take into account single and double
+ * quotes.
+ */
+ if ((q = strchr(panic_action, ' '))) {
+ /*
+ * need to use a static buffer, because mallocing memory in a signal handler
+ * is a bad idea and can result in deadlock.
+ */
+ len = snprintf(filename, sizeof(filename), "%.*s", (int)(q - panic_action), panic_action);
+ if (is_truncated(len, sizeof(filename))) {
+ fr_strerror_printf("Failed writing panic_action to temporary buffer (truncated)");
+ return -1;
+ }
+ p = filename;
+ } else {
+ p = panic_action;
+ }
+
+ if (stat(p, &statbuf) == 0) {
+#ifdef S_IWOTH
+ if ((statbuf.st_mode & S_IWOTH) != 0) {
+ fr_strerror_printf("panic_action file \"%s\" is globally writable", p);
+ return -1;
+ }
+#endif
+ }
+
+ return 0;
+}
+
+/** Prints a simple backtrace (if execinfo is available) and calls panic_action if set.
+ *
+ * @param sig caught
+ */
+void 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;
+
+ /*
+ * Makes the backtraces slightly cleaner
+ */
+ memset(cmd, 0, sizeof(cmd));
+
+ FR_FAULT_LOG("CAUGHT SIGNAL: %s", strsignal(sig));
+
+ /*
+ * Check for administrator sanity.
+ */
+ if (fr_fault_check_permissions() < 0) {
+ FR_FAULT_LOG("Refusing to execute panic action: %s", fr_strerror());
+ goto finish;
+ }
+
+ /*
+ * Run the callback if one was registered
+ */
+ if (panic_cb && (panic_cb(sig) < 0)) goto finish;
+
+ /*
+ * 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
+ {
+ size_t frame_count, i;
+ void *stack[MAX_BT_FRAMES];
+ char **strings;
+
+ frame_count = backtrace(stack, MAX_BT_FRAMES);
+
+ FR_FAULT_LOG("Backtrace of last %zu frames:", frame_count);
+
+ /*
+ * Only use backtrace_symbols() if we don't have a logging fd.
+ * If the server has experienced memory corruption, there's
+ * a high probability that calling backtrace_symbols() which
+ * mallocs more memory, will fail.
+ */
+ if (fr_fault_log_fd < 0) {
+ strings = backtrace_symbols(stack, frame_count);
+ for (i = 0; i < frame_count; i++) {
+ FR_FAULT_LOG("%s", strings[i]);
+ }
+ free(strings);
+ } else {
+ backtrace_symbols_fd(stack, frame_count, fr_fault_log_fd);
+ }
+ }
+#endif
+
+ /* No panic action set... */
+ if (panic_action[0] == '\0') {
+ FR_FAULT_LOG("No panic action set");
+ goto finish;
+ }
+
+ /* 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:
+ FR_FAULT_LOG("Panic action too long");
+ fr_exit_now(1);
+ }
+ left -= ret;
+ p = q + 2;
+ }
+ if (strlen(p) >= left) goto oob;
+ strlcpy(out, p, left);
+
+ FR_FAULT_LOG("Calling: %s", cmd);
+
+ {
+ bool disable = false;
+
+ /*
+ * Here we temporarily enable the dumpable flag so if GBD or LLDB
+ * is called in the panic_action, they can pattach tot he running
+ * process.
+ */
+ if (fr_get_dumpable_flag() == 0) {
+ if ((fr_set_dumpable_flag(true) < 0) || !fr_get_dumpable_flag()) {
+ FR_FAULT_LOG("Failed setting dumpable flag, pattach may not work: %s", fr_strerror());
+ } else {
+ disable = true;
+ }
+ FR_FAULT_LOG("Temporarily setting PR_DUMPABLE to 1");
+ }
+
+ code = system(cmd);
+
+ /*
+ * We only want to error out here, if dumpable was originally disabled
+ * and we managed to change the value to enabled, but failed
+ * setting it back to disabled.
+ */
+ if (disable) {
+ FR_FAULT_LOG("Resetting PR_DUMPABLE to 0");
+ if (fr_set_dumpable_flag(false) < 0) {
+ FR_FAULT_LOG("Failed reseting dumpable flag to off: %s", fr_strerror());
+ FR_FAULT_LOG("Exiting due to insecure process state");
+ fr_exit_now(1);
+ }
+ }
+ }
+
+ FR_FAULT_LOG("Panic action exited with %i", code);
+
+finish:
+#ifdef SIGUSR1
+ if (sig == SIGUSR1) {
+ return;
+ }
+#endif
+ fr_exit_now(1);
+}
+
+#ifdef SIGABRT
+/** Work around debuggers which can't backtrace past the signal handler
+ *
+ * At least this provides us some information when we get talloc errors.
+ */
+static void _fr_talloc_fault(char const *reason)
+{
+ fr_fault_log("talloc abort: %s\n", reason);
+ fr_fault(SIGABRT);
+}
+#endif
+
+/** Wrapper to pass talloc log output to our fr_fault_log function
+ *
+ */
+static void _fr_talloc_log(char const *msg)
+{
+ fr_fault_log("%s\n", msg);
+}
+
+/** Generate a talloc memory report for a context and print to stderr/stdout
+ *
+ * @param ctx to generate a report for, may be NULL in which case the root context is used.
+ */
+int fr_log_talloc_report(TALLOC_CTX *ctx)
+{
+ FILE *log;
+ char const *null_ctx = NULL;
+ int i = 0;
+ int fd;
+
+ fd = dup(fr_fault_log_fd);
+ if (fd < 0) {
+ fr_strerror_printf("Couldn't write memory report, failed to dup log fd: %s", fr_syserror(errno));
+ return -1;
+ }
+ log = fdopen(fd, "w");
+ if (!log) {
+ close(fd);
+ fr_strerror_printf("Couldn't write memory report, fdopen failed: %s", fr_syserror(errno));
+ return -1;
+ }
+
+ fprintf(log, "Current state of talloced memory:\n");
+ if (ctx) {
+ null_ctx = talloc_get_name(NULL);
+ }
+
+ if (!ctx) {
+ talloc_report_full(NULL, log);
+ } else do {
+ fprintf(log, "Context level %i", i++);
+
+ talloc_report_full(ctx, log);
+ } while ((ctx = talloc_parent(ctx)) && (talloc_get_name(ctx) != null_ctx)); /* Stop before we hit NULL ctx */
+
+ fclose(log);
+
+ return 0;
+}
+
+/** Signal handler to print out a talloc memory report
+ *
+ * @param sig caught
+ */
+static void _fr_fault_mem_report(int sig)
+{
+ fr_fault_log("CAUGHT SIGNAL: %s\n", strsignal(sig));
+
+ if (fr_log_talloc_report(NULL) < 0) fr_perror("memreport");
+}
+
+static int _fr_disable_null_tracking(UNUSED bool *p)
+{
+ talloc_disable_null_tracking();
+ return 0;
+}
+
+/** 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 bool 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';
+ }
+
+ /*
+ * Check for administrator sanity.
+ */
+ if (fr_fault_check_permissions() < 0) return -1;
+
+ /* 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;
+ /*
+ * Use this instead of abort so we get a
+ * full backtrace with broken versions of LLDB
+ */
+ talloc_set_abort_fn(_fr_talloc_fault);
+#endif
+#ifdef SIGFPE
+ if (fr_set_signal(SIGFPE, fr_fault) < 0) return -1;
+#endif
+
+#ifdef SIGUSR1
+ if (fr_set_signal(SIGUSR1, fr_fault) < 0) return -1;
+#endif
+
+#ifdef SIGUSR2
+ if (fr_set_signal(SIGUSR2, _fr_fault_mem_report) < 0) return -1;
+#endif
+
+ /*
+ * Setup the default logger
+ */
+ if (!fr_fault_log) fr_fault_set_log_fn(NULL);
+ talloc_set_log_fn(_fr_talloc_log);
+
+ /*
+ * Needed for memory reports
+ *
+ * Disable null tracking on exit, else valgrind complains
+ */
+ {
+ TALLOC_CTX *autofree;
+ bool *marker;
+
+ talloc_enable_null_tracking();
+
+ autofree = talloc_autofree_context();
+ marker = talloc(autofree, bool);
+ talloc_set_destructor(marker, _fr_disable_null_tracking);
+ }
+
+ /*
+ * If were using glibc malloc > 2.4 this scribbles over
+ * uninitialised and freed memory, to make memory issues easier
+ * to track down.
+ */
+#if defined(HAVE_MALLOPT) && !defined(NDEBUG)
+ mallopt(M_PERTURB, 0x42);
+ mallopt(M_CHECK_ACTION, 3);
+#endif
+ }
+ setup = true;
+
+ return 0;
+}
+
+/** Set a callback to be called before fr_fault()
+ *
+ * @param func to execute. If callback returns < 0
+ * fr_fault will exit before running panic_action code.
+ */
+void fr_fault_set_cb(fr_fault_cb_t func)
+{
+ panic_cb = func;
+};
+
+/** Default logger, logs output to stderr
+ *
+ */
+static void CC_HINT(format (printf, 1, 2)) _fr_fault_log(char const *msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg);
+ vfprintf(stderr, msg, ap);
+ va_end(ap);
+}
+
+
+/** Set a file descriptor to log panic_action output to.
+ *
+ * @param func to call to output log messages.
+ */
+void fr_fault_set_log_fn(fr_fault_log_t func)
+{
+ fr_fault_log = func ? func : _fr_fault_log;
+}
+
+/** Set a file descriptor to log memory reports to.
+ *
+ * @param fd to write output to.
+ */
+void fr_fault_set_log_fd(int fd)
+{
+ fr_fault_log_fd = fd;
+}
+
+
+#ifdef WITH_VERIFY_PTR
+
+/*
+ * Verify a VALUE_PAIR
+ */
+inline void fr_verify_vp(VALUE_PAIR const *vp)
+{
+ (void) talloc_get_type_abort(vp, VALUE_PAIR);
+
+ if (vp->data.ptr) switch (vp->da->type) {
+ case PW_TYPE_OCTETS:
+ case PW_TYPE_TLV:
+ {
+ size_t len;
+
+ if (!talloc_get_type(vp->data.ptr, uint8_t)) {
+ fr_perror("Type check failed for attribute \"%s\"", vp->da->name);
+ (void) talloc_get_type_abort(vp->data.ptr, uint8_t);
+ }
+
+ len = talloc_array_length(vp->vp_octets);
+ if (vp->length > len) {
+ fr_perror("VALUE_PAIR length %zu does not equal uint8_t buffer length %zu", vp->length, len);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+ }
+ break;
+
+ case PW_TYPE_STRING:
+ {
+ size_t len;
+
+ if (!talloc_get_type(vp->data.ptr, char)) {
+ fr_perror("Type check failed for attribute \"%s\"", vp->da->name);
+ (void) talloc_get_type_abort(vp->data.ptr, char);
+ }
+
+ len = (talloc_array_length(vp->vp_strvalue) - 1);
+ if (vp->length > len) {
+ fr_perror("VALUE_PAIR %s length %zu is too small for char buffer length %zu",
+ vp->da->name, vp->length, len);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+ if (vp->vp_strvalue[vp->length] != '\0') {
+ fr_perror("VALUE_PAIR %s buffer not \\0 terminated", vp->da->name);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*
+ * Verify a pair list
+ */
+void fr_verify_list(TALLOC_CTX *expected, VALUE_PAIR *vps)
+{
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+ TALLOC_CTX *parent;
+
+ for (vp = fr_cursor_init(&cursor, &vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ VERIFY_VP(vp);
+
+ parent = talloc_parent(vp);
+ if (expected && (parent != expected)) {
+ fr_perror("Expected VALUE_PAIR (%s) to be parented by %p (%s), "
+ "but parented by %p (%s)",
+ vp->da->name,
+ expected, talloc_get_name(expected),
+ parent, parent ? talloc_get_name(parent) : "NULL");
+
+ fr_log_talloc_report(expected);
+ if (parent) fr_log_talloc_report(parent);
+
+ assert(0);
+ }
+
+ }
+}
+#endif
*/
typedef struct dict_stat_t {
struct dict_stat_t *next;
- char *name;
- time_t mtime;
+ struct stat stat_buf;
} dict_stat_t;
-static char *stat_root_dir = NULL;
-static char *stat_root_file = NULL;
-
static dict_stat_t *stat_head = NULL;
static dict_stat_t *stat_tail = NULL;
const FR_NAME_NUMBER dict_attr_types[] = {
{ "integer", PW_TYPE_INTEGER },
{ "string", PW_TYPE_STRING },
- { "ipaddr", PW_TYPE_IPADDR },
+ { "ipaddr", PW_TYPE_IPV4_ADDR },
{ "date", PW_TYPE_DATE },
{ "abinary", PW_TYPE_ABINARY },
{ "octets", PW_TYPE_OCTETS },
{ "ifid", PW_TYPE_IFID },
- { "ipv6addr", PW_TYPE_IPV6ADDR },
- { "ipv6prefix", PW_TYPE_IPV6PREFIX },
+ { "ipv6addr", PW_TYPE_IPV6_ADDR },
+ { "ipv6prefix", PW_TYPE_IPV6_PREFIX },
{ "byte", PW_TYPE_BYTE },
{ "short", PW_TYPE_SHORT },
{ "ether", PW_TYPE_ETHERNET },
- { "combo-ip", PW_TYPE_COMBO_IP },
+ { "combo-ip", PW_TYPE_IP_ADDR },
{ "tlv", PW_TYPE_TLV },
{ "signed", PW_TYPE_SIGNED },
{ "extended", PW_TYPE_EXTENDED },
{ "int32", PW_TYPE_SIGNED },
{ "integer64", PW_TYPE_INTEGER64 },
{ "uint64", PW_TYPE_INTEGER64 },
- { "ipv4prefix", PW_TYPE_IPV4PREFIX },
- { "cidr", PW_TYPE_IPV4PREFIX },
+ { "ipv4prefix", PW_TYPE_IPV4_PREFIX },
+ { "cidr", PW_TYPE_IPV4_PREFIX },
{ "vsa", PW_TYPE_VSA },
{ NULL, 0 }
};
[PW_TYPE_INVALID] = { ~0, 0 },
[PW_TYPE_STRING] = { 0, ~0 },
[PW_TYPE_INTEGER] = {4, 4 },
- [PW_TYPE_IPADDR] = {4, 4},
+ [PW_TYPE_IPV4_ADDR] = {4, 4},
[PW_TYPE_DATE] = {4, 4},
[PW_TYPE_ABINARY] = {32, ~0},
[PW_TYPE_OCTETS] = {0, ~0},
[PW_TYPE_IFID] = {8, 8},
- [PW_TYPE_IPV6ADDR] = { 16, 16},
- [PW_TYPE_IPV6PREFIX] = {2, 18},
+ [PW_TYPE_IPV6_ADDR] = { 16, 16},
+ [PW_TYPE_IPV6_PREFIX] = {2, 18},
[PW_TYPE_BYTE] = {1, 1},
[PW_TYPE_SHORT] = {2, 2},
[PW_TYPE_ETHERNET] = {6, 6},
[PW_TYPE_SIGNED] = {4, 4},
- [PW_TYPE_COMBO_IP] = {4, 16},
+ [PW_TYPE_IP_ADDR] = {4, 16},
[PW_TYPE_TLV] = {2, ~0},
[PW_TYPE_EXTENDED] = {2, ~0},
[PW_TYPE_LONG_EXTENDED] = {3, ~0},
[PW_TYPE_EVS] = {6, ~0},
[PW_TYPE_INTEGER64] = {8, 8},
- [PW_TYPE_IPV4PREFIX] = {6, 6},
+ [PW_TYPE_IPV4_PREFIX] = {6, 6},
[PW_TYPE_VSA] = {4, ~0}
};
{
dict_stat_t *this, *next;
- free(stat_root_dir);
- stat_root_dir = NULL;
- free(stat_root_file);
- stat_root_file = NULL;
-
if (!stat_head) {
stat_tail = NULL;
return;
for (this = stat_head; this != NULL; this = next) {
next = this->next;
- free(this->name);
free(this);
}
/*
* Add an entry to the list of stat buffers.
*/
-static void dict_stat_add(char const *name, struct stat const *stat_buf)
+static void dict_stat_add(struct stat const *stat_buf)
{
dict_stat_t *this;
if (!this) return;
memset(this, 0, sizeof(*this));
- this->name = strdup(name);
- this->mtime = stat_buf->st_mtime;
+ memcpy(&(this->stat_buf), stat_buf, sizeof(this->stat_buf));
if (!stat_head) {
stat_head = stat_tail = this;
* See if any dictionaries have changed. If not, don't
* do anything.
*/
-static int dict_stat_check(char const *root_dir, char const *root_file)
+static int dict_stat_check(char const *dir, char const *file)
{
- struct stat buf;
+ struct stat stat_buf;
dict_stat_t *this;
+ char buffer[2048];
- if (!stat_root_dir) return 0;
- if (!stat_root_file) return 0;
-
- if (strcmp(root_dir, stat_root_dir) != 0) return 0;
- if (strcmp(root_file, stat_root_file) != 0) return 0;
+ /*
+ * Nothing cached, all files are new.
+ */
+ if (!stat_head) return 0;
- if (!stat_head) return 0; /* changed, reload */
+ /*
+ * Stat the file.
+ */
+ snprintf(buffer, sizeof(buffer), "%s/%s", dir, file);
+ if (stat(buffer, &stat_buf) < 0) return 0;
+ /*
+ * Find the cache entry.
+ * FIXME: use a hash table.
+ * FIXME: check dependencies, via children.
+ * if A loads B and B changes, we probably want
+ * to reload B at the minimum.
+ */
for (this = stat_head; this != NULL; this = this->next) {
- if (stat(this->name, &buf) < 0) return 0;
+ if (this->stat_buf.st_dev != stat_buf.st_dev) continue;
+ if (this->stat_buf.st_ino != stat_buf.st_ino) continue;
+
+ /*
+ * The file has changed. Re-read it.
+ */
+ if (this->stat_buf.st_mtime < stat_buf.st_mtime) return 0;
- if (buf.st_mtime != this->mtime) return 0;
+ /*
+ * The file is the same. Ignore it.
+ */
+ return 1;
}
- return 1;
+ /*
+ * Not in the cache.
+ */
+ return 0;
}
typedef struct fr_pool_t {
/*
* Add an attribute to the dictionary.
*/
-int dict_addattr(char const *name, int attr, unsigned int vendor, int type,
+int dict_addattr(char const *name, int attr, unsigned int vendor, PW_TYPE type,
ATTR_FLAGS flags)
{
size_t namelen;
*/
if (flags.extended || flags.long_extended || flags.evs) {
if (vendor && (vendor < FR_MAX_VENDOR)) {
- fr_strerror_printf("dict_addattr: VSAs cannot use the \"extended\" or \"evs\" attribute formats.");
+ fr_strerror_printf("dict_addattr: VSAs cannot use the \"extended\" or \"evs\" attribute formats");
return -1;
}
if (flags.has_tag
|| flags.array
#endif
|| (flags.encrypt != FLAG_ENCRYPT_NONE)) {
- fr_strerror_printf("dict_addattr: The \"extended\" attributes MUST NOT have any flags set.");
+ fr_strerror_printf("dict_addattr: The \"extended\" attributes MUST NOT have any flags set");
return -1;
}
}
}
if (vendor && flags.concat) {
- fr_strerror_printf("VSAs cannot have the \"concat\" flag set.");
+ fr_strerror_printf("VSAs cannot have the \"concat\" flag set");
return -1;
}
if (flags.concat && (type != PW_TYPE_OCTETS)) {
- fr_strerror_printf("The \"concat\" flag can only be set for attributes of type \"octets\".");
+ fr_strerror_printf("The \"concat\" flag can only be set for attributes of type \"octets\"");
return -1;
}
if (flags.concat && (flags.has_tag || flags.array || flags.is_tlv || flags.has_tlv ||
flags.length || flags.evs || flags.extended || flags.long_extended ||
(flags.encrypt != FLAG_ENCRYPT_NONE))) {
- fr_strerror_printf("The \"concat\" flag cannot be used with any other flag.");
+ fr_strerror_printf("The \"concat\" flag cannot be used with any other flag");
return -1;
}
* properly.
*/
if ((dv->type == 1) && (attr >= 256) && !flags.is_tlv) {
- fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (larger than 255).");
+ fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (larger than 255)");
return -1;
} /* else 256..65535 are allowed */
*/
if ((n = fr_pool_alloc(sizeof(*n) + namelen)) == NULL) {
oom:
- fr_strerror_printf("dict_adnttr: out of memory");
+ fr_strerror_printf("dict_addattr: out of memory");
return -1;
}
a = fr_hash_table_finddata(attributes_byname, n);
if (a && (strcasecmp(a->name, n->name) == 0)) {
if (a->attr != n->attr) {
- fr_strerror_printf("dict_adnttr: Duplicate attribute name %s", name);
+ fr_strerror_printf("dict_addattr: Duplicate attribute name %s", name);
fr_pool_free(n);
return -1;
}
fr_hash_table_delete(attributes_byvalue, a);
if (!fr_hash_table_replace(attributes_byname, n)) {
- fr_strerror_printf("dict_adnttr: Internal error storing attribute %s", name);
+ fr_strerror_printf("dict_addattr: Internal error storing attribute %s", name);
fr_pool_free(n);
return -1;
}
* by value) we want to use the NEW name.
*/
if (!fr_hash_table_replace(attributes_byvalue, n)) {
- fr_strerror_printf("dict_adnttr: Failed inserting attribute name %s", name);
+ fr_strerror_printf("dict_addattr: Failed inserting attribute name %s", name);
return -1;
}
/*
* Hacks for combo-IP
*/
- if (n->type == PW_TYPE_COMBO_IP) {
+ if (n->type == PW_TYPE_IP_ADDR) {
DICT_ATTR *v4, *v6;
v4 = fr_pool_alloc(sizeof(*v4));
if (!v4) goto oom;
v6 = fr_pool_alloc(sizeof(*v6));
- if (!v6) {
- free(v4);
- goto oom;
- }
+ if (!v6) goto oom;
memcpy(v4, n, sizeof(*v4));
- v4->type = PW_TYPE_IPADDR;
+ v4->type = PW_TYPE_IPV4_ADDR;
memcpy(v6, n, sizeof(*v6));
- v6->type = PW_TYPE_IPV6ADDR;
-
- if (!fr_hash_table_insert(attributes_combo, v4)) {
+ v6->type = PW_TYPE_IPV6_ADDR;
+ if (!fr_hash_table_replace(attributes_combo, v4)) {
fr_strerror_printf("dict_addattr: Failed inserting attribute name %s - IPv4", name);
- free(v4);
- free(v6);
return -1;
}
- if (!fr_hash_table_insert(attributes_combo, v6)) {
+ if (!fr_hash_table_replace(attributes_combo, v6)) {
fr_strerror_printf("dict_addattr: Failed inserting attribute name %s - IPv6", name);
- free(v6);
return -1;
}
}
int dict_addvalue(char const *namestr, char const *attrstr, int value)
{
size_t length;
- DICT_ATTR const *dattr;
+ DICT_ATTR const *da;
DICT_VALUE *dval;
static DICT_ATTR const *last_attr = NULL;
* caching the last attribute.
*/
if (last_attr && (strcasecmp(attrstr, last_attr->name) == 0)) {
- dattr = last_attr;
+ da = last_attr;
} else {
- dattr = dict_attrbyname(attrstr);
- last_attr = dattr;
+ da = dict_attrbyname(attrstr);
+ last_attr = da;
}
/*
* Remember which attribute is associated with this
* value, if possible.
*/
- if (dattr) {
- if (dattr->flags.has_value_alias) {
+ if (da) {
+ if (da->flags.has_value_alias) {
fr_strerror_printf("dict_addvalue: Cannot add VALUE for ATTRIBUTE \"%s\": It already has a VALUE-ALIAS", attrstr);
return -1;
}
- dval->attr = dattr->attr;
- dval->vendor = dattr->vendor;
+ dval->attr = da->attr;
+ dval->vendor = da->vendor;
/*
* Enforce valid values
*
* Don't worry about fixups...
*/
- switch (dattr->type) {
+ switch (da->type) {
case PW_TYPE_BYTE:
if (value > 255) {
fr_pool_free(dval);
default:
fr_pool_free(dval);
fr_strerror_printf("dict_addvalue: VALUEs cannot be defined for attributes of type '%s'",
- fr_int2str(dict_attr_types, dattr->type, "?Unknown?"));
+ fr_int2str(dict_attr_types, da->type, "?Unknown?"));
return -1;
}
} else {
memcpy(&tmp, &dval, sizeof(tmp));
if (!fr_hash_table_insert(values_byname, tmp)) {
- if (dattr) {
+ if (da) {
DICT_VALUE *old;
/*
* name and value. There are lots in
* dictionary.ascend.
*/
- old = dict_valbyname(dattr->attr, dattr->vendor, namestr);
+ old = dict_valbyname(da->attr, da->vendor, namestr);
if (old && (old->value == dval->value)) {
fr_pool_free(dval);
return 0;
if (*pvalue) {
da = dict_attrbyvalue(*pvalue, *pvendor);
if (!da) {
- fr_strerror_printf("Parent attribute is undefined.");
+ fr_strerror_printf("Parent attribute is undefined");
return -1;
}
break;
case PW_TYPE_DATE:
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
case PW_TYPE_INTEGER:
case PW_TYPE_SIGNED:
length = 4;
length = 8;
break;
- case PW_TYPE_IPV6ADDR:
+ case PW_TYPE_IPV6_ADDR:
length = 16;
break;
break;
}
- flags.length = length;
+ flags.length = length;
} else { /* argc == 4: we have options */
char *key, *next, *last;
flags.array = 1;
switch (type) {
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
case PW_TYPE_BYTE:
case PW_TYPE_SHORT:
case PW_TYPE_INTEGER:
int argc)
{
int value;
- int continuation = 0;
+ bool continuation = false;
char const *format = NULL;
if ((argc < 2) || (argc > 3)) {
fn, line, p);
return -1;
}
- continuation = 1;
+ continuation = true;
if ((value != VENDORPEC_WIMAX) ||
(type != 1) || (length != 1)) {
}
+ /*
+ * Check if we've loaded this file before. If so, ignore it.
+ */
+ p = strrchr(fn, FR_DIR_SEP);
+ if (p) {
+ *p = '\0';
+ if (dict_stat_check(fn, p + 1)) {
+ *p = FR_DIR_SEP;
+ return 0;
+ }
+ *p = FR_DIR_SEP;
+ }
+
if ((fp = fopen(fn, "r")) == NULL) {
if (!src_file) {
fr_strerror_printf("dict_init: Couldn't open dictionary \"%s\": %s",
- fn, strerror(errno));
+ fn, fr_syserror(errno));
} else {
fr_strerror_printf("dict_init: %s[%d]: Couldn't open dictionary \"%s\": %s",
- src_file, src_line, fn, strerror(errno));
+ src_file, src_line, fn, fr_syserror(errno));
}
return -2;
}
}
#endif
- dict_stat_add(fn, &statbuf);
+ dict_stat_add(&statbuf);
/*
* Seed the random pool with data.
* Free the dictionaries, and the stat cache.
*/
dict_free();
- stat_root_dir = strdup(dir);
- stat_root_file = strdup(fn);
/*
* Create the table of vendor by name. There MAY NOT
vendor = dict_vendorbyname(buffer);
if (!vendor) {
- fr_strerror_printf("Unknown vendor name in "
- "attribute name \"%s\"",
+ fr_strerror_printf("Unknown attribute \"%s\"",
attribute);
return NULL;
}
* Attr-%d
*/
if (strncasecmp(p, "Attr-", 5) != 0) {
- fr_strerror_printf("Invalid format in attribute name \"%s\"",
+ fr_strerror_printf("Unknown attribute \"%s\"",
attribute);
return NULL;
}
*/
DICT_ATTR const *dict_attrbyvalue(unsigned int attr, unsigned int vendor)
{
- DICT_ATTR dattr;
+ DICT_ATTR da;
if ((attr > 0) && (attr < 256) && !vendor) return dict_base_attrs[attr];
- dattr.attr = attr;
- dattr.vendor = vendor;
+ da.attr = attr;
+ da.vendor = vendor;
- return fr_hash_table_finddata(attributes_byvalue, &dattr);
+ return fr_hash_table_finddata(attributes_byvalue, &da);
}
DICT_ATTR const *dict_attrbytype(unsigned int attr, unsigned int vendor,
PW_TYPE type)
{
- DICT_ATTR dattr;
+ DICT_ATTR da;
- dattr.attr = attr;
- dattr.vendor = vendor;
- dattr.type = type;
+ da.attr = attr;
+ da.vendor = vendor;
+ da.type = type;
- return fr_hash_table_finddata(attributes_combo, &dattr);
+ return fr_hash_table_finddata(attributes_combo, &da);
}
/**
unsigned int *pattr, unsigned int *pvendor)
{
unsigned int attr, vendor;
- DICT_ATTR dattr;
+ DICT_ATTR da;
if (!parent || !pattr || !pvendor) return false;
/*
* Bootstrap by starting off with the parents values.
*/
- dattr.attr = parent->attr;
- dattr.vendor = parent->vendor;
+ da.attr = parent->attr;
+ da.vendor = parent->vendor;
/*
* Do various butchery to insert the "attr" value.
* EEVID 000000AA EVS with vendor VID, attr AAA
* EEVID DDCCBBAA EVS with TLVs
*/
- if (!dattr.vendor) {
- dattr.vendor = parent->attr * FR_MAX_VENDOR;
- dattr.vendor |= vendor;
- dattr.attr = attr;
+ if (!da.vendor) {
+ da.vendor = parent->attr * FR_MAX_VENDOR;
+ da.vendor |= vendor;
+ da.attr = attr;
} else {
int i;
for (i = MAX_TLV_NEST - 1; i >= 0; i--) {
if ((parent->attr & (fr_attr_mask[i] << fr_attr_shift[i]))) {
- dattr.attr |= (attr & fr_attr_mask[i + 1]) << fr_attr_shift[i + 1];
+ da.attr |= (attr & fr_attr_mask[i + 1]) << fr_attr_shift[i + 1];
goto find;
}
}
#if 0
fprintf(stderr, "LOOKING FOR %08x %08x + %08x %08x --> %08x %08x\n",
parent->vendor, parent->attr, attr, vendor,
- dattr.vendor, dattr.attr);
+ da.vendor, da.attr);
#endif
- *pattr = dattr.attr;
- *pvendor = dattr.vendor;
+ *pattr = da.attr;
+ *pvendor = da.vendor;
return true;
}
DICT_ATTR const *dict_attrbyparent(DICT_ATTR const *parent, unsigned int attr, unsigned int vendor)
{
unsigned int my_attr, my_vendor;
- DICT_ATTR dattr;
+ DICT_ATTR da;
my_attr = attr;
my_vendor = vendor;
if (!dict_attr_child(parent, &my_attr, &my_vendor)) return NULL;
- dattr.attr = my_attr;
- dattr.vendor = my_vendor;
+ da.attr = my_attr;
+ da.vendor = my_vendor;
- return fr_hash_table_finddata(attributes_byvalue, &dattr);
+ return fr_hash_table_finddata(attributes_byvalue, &da);
}
}
/*
+ * Get an attribute by its name, where the name might have a tag
+ * or something else after it.
+ */
+DICT_ATTR const *dict_attrbytagged_name(char const *name)
+{
+ DICT_ATTR *da;
+ char *p;
+ uint32_t buffer[(sizeof(*da) + DICT_ATTR_MAX_NAME_LEN + 3)/4];
+
+ if (!name) return NULL;
+
+ da = (DICT_ATTR *) buffer;
+ strlcpy(da->name, name, DICT_ATTR_MAX_NAME_LEN + 1);
+
+ /*
+ * The name might have a tag or array reference. That
+ * isn't properly part of the name, and can be ignored on
+ * lookup.
+ */
+ for (p = &da->name[0]; *p; p++) {
+ if (*p == ':') {
+ *p = '\0';
+ break;
+ }
+
+ if (*p == '[') {
+ *p = '\0';
+ break;
+ }
+ }
+
+ return fr_hash_table_finddata(attributes_byname, da);
+}
+
+/*
* Associate a value with an attribute and return it.
*/
DICT_VALUE *dict_valbyattr(unsigned int attr, unsigned int vendor, int value)
struct fr_event_list_t {
fr_heap_t *times;
- int changed;
+ bool changed;
int exit;
fr_event_status_t status;
struct timeval now;
- int dispatch;
+ bool dispatch;
int max_readers;
+ int num_readers;
fr_event_fd_t readers[FR_EV_MAX_FDS];
};
fr_event_callback_t callback;
void *ctx;
struct timeval when;
- fr_event_t **ev_p;
+ fr_event_t **parent;
int heap;
};
}
-void fr_event_list_free(fr_event_list_t *el)
+static int _event_list_free(fr_event_list_t *list)
{
+ fr_event_list_t *el = list;
fr_event_t *ev;
- if (!el) return;
-
while ((ev = fr_heap_peek(el->times)) != NULL) {
fr_event_delete(el, &ev);
}
fr_heap_delete(el->times);
- free(el);
+
+ return 0;
}
-fr_event_list_t *fr_event_list_create(fr_event_status_t status)
+fr_event_list_t *fr_event_list_create(TALLOC_CTX *ctx, fr_event_status_t status)
{
int i;
fr_event_list_t *el;
- el = malloc(sizeof(*el));
- if (!el) return NULL;
- memset(el, 0, sizeof(*el));
+ el = talloc_zero(ctx, fr_event_list_t);
+ if (!fr_assert(el)) {
+ return NULL;
+ }
+ talloc_set_destructor(el, _event_list_free);
- el->times = fr_heap_create(fr_event_list_time_cmp,
- offsetof(fr_event_t, heap));
+ el->times = fr_heap_create(fr_event_list_time_cmp, offsetof(fr_event_t, heap));
if (!el->times) {
- fr_event_list_free(el);
+ talloc_free(el);
return NULL;
}
}
el->status = status;
- el->changed = 1; /* force re-set of fds's */
+ el->changed = true; /* force re-set of fds's */
return el;
}
+int fr_event_list_num_fds(fr_event_list_t *el)
+{
+ if (!el) return 0;
+
+ return el->num_readers;
+}
+
int fr_event_list_num_elements(fr_event_list_t *el)
{
if (!el) return 0;
}
-int fr_event_delete(fr_event_list_t *el, fr_event_t **ev_p)
+int fr_event_delete(fr_event_list_t *el, fr_event_t **parent)
{
+ int ret;
+
fr_event_t *ev;
- if (!el || !ev_p || !*ev_p) return 0;
+ if (!el || !parent || !*parent) return 0;
- ev = *ev_p;
- if (ev->ev_p) *(ev->ev_p) = NULL;
- *ev_p = NULL;
+#ifndef NDEBUG
+ /*
+ * Validate the event_t struct to detect memory issues early.
+ */
+ ev = talloc_get_type_abort(*parent, fr_event_t);
- fr_heap_extract(el->times, ev);
- free(ev);
+#else
+ ev = *parent;
+#endif
- return 1;
+ if (ev->parent) {
+ fr_assert(*(ev->parent) == ev);
+ *ev->parent = NULL;
+ }
+ *parent = NULL;
+
+ ret = fr_heap_extract(el->times, ev);
+ fr_assert(ret == 1); /* events MUST be in the heap */
+ talloc_free(ev);
+
+ return ret;
}
-int fr_event_insert(fr_event_list_t *el,
- fr_event_callback_t callback,
- void *ctx, struct timeval *when,
- fr_event_t **ev_p)
+int fr_event_insert(fr_event_list_t *el, fr_event_callback_t callback, void *ctx, struct timeval *when,
+ fr_event_t **parent)
{
fr_event_t *ev;
- if (!el || !callback | !when || (when->tv_usec >= USEC)) return 0;
+ if (!el) {
+ fr_strerror_printf("Invalid arguments (NULL event list)");
+ return 0;
+ }
+
+ if (!callback) {
+ fr_strerror_printf("Invalid arguments (NULL callback)");
+ return 0;
+ }
+
+ if (!when || (when->tv_usec >= USEC)) {
+ fr_strerror_printf("Invalid arguments (time)");
+ return 0;
+ }
- if (ev_p && *ev_p) fr_event_delete(el, ev_p);
+ if (!parent) {
+ fr_strerror_printf("Invalid arguments (NULL parent)");
+ return 0;
+ }
- ev = malloc(sizeof(*ev));
- if (!ev) return 0;
- memset(ev, 0, sizeof(*ev));
+ if (*parent) fr_event_delete(el, parent);
+ ev = talloc_zero(el, fr_event_t);
ev->callback = callback;
ev->ctx = ctx;
ev->when = *when;
- ev->ev_p = ev_p;
+ ev->parent = parent;
if (!fr_heap_insert(el->times, ev)) {
- free(ev);
+ talloc_free(ev);
return 0;
}
- if (ev_p) *ev_p = ev;
+ *parent = ev;
return 1;
}
return 0;
}
+#ifndef NDEBUG
+ ev = talloc_get_type_abort(ev, fr_event_t);
+#endif
+
/*
* See if it's time to do this one.
*/
int i;
fr_event_fd_t *ef;
- if (!el || (fd < 0) || !handler || !ctx) return 0;
+ if (!el) {
+ fr_strerror_printf("Invalid arguments (NULL event list)");
+ return 0;
+ }
- if (type != 0) return 0;
+ if (!handler) {
+ fr_strerror_printf("Invalid arguments (NULL handler)");
+ return 0;
+ }
- if (el->max_readers >= FR_EV_MAX_FDS) return 0;
+ if (!ctx) {
+ fr_strerror_printf("Invalid arguments (NULL ctx)");
+ return 0;
+ }
+
+ if (fd < 0) {
+ fr_strerror_printf("Invalid arguments (bad FD %i)", fd);
+ return 0;
+ }
+
+ if (type != 0) {
+ fr_strerror_printf("Invalid type %i", type);
+ return 0;
+ }
+
+ if (el->max_readers >= FR_EV_MAX_FDS) {
+ fr_strerror_printf("Too many readers");
+ return 0;
+ }
ef = NULL;
for (i = 0; i <= el->max_readers; i++) {
if (el->readers[i].fd == fd) {
if ((el->readers[i].handler != handler) ||
(el->readers[i].ctx != ctx)) {
+ fr_strerror_printf("Multiple handlers for same FD");
return 0;
}
if (el->readers[i].fd < 0) {
ef = &el->readers[i];
+ el->num_readers++;
if (i == el->max_readers) el->max_readers = i + 1;
break;
}
}
- if (!ef) return 0;
+ if (!ef) {
+ fr_strerror_printf("Failed assigning FD");
+ return 0;
+ }
ef->handler = handler;
ef->ctx = ctx;
ef->fd = fd;
- el->changed = 1;
+ el->changed = true;
return 1;
}
for (i = 0; i < el->max_readers; i++) {
if (el->readers[i].fd == fd) {
el->readers[i].fd = -1;
+ el->num_readers--;
+
if ((i + 1) == el->max_readers) el->max_readers = i;
- el->changed = 1;
+ el->changed = true;
return 1;
}
}
el->exit = code;
}
+bool fr_event_loop_exiting(fr_event_list_t *el)
+{
+ return (el->exit != 0);
+}
int fr_event_loop(fr_event_list_t *el)
{
fd_set read_fds, master_fds;
el->exit = 0;
- el->dispatch = 1;
- el->changed = 1;
+ el->dispatch = true;
+ el->changed = true;
while (!el->exit) {
/*
* Cache the list of FD's to watch.
*/
if (el->changed) {
+#ifdef __clang_analyzer__
+ memset(&master_fds, 0, sizeof(master_fds));
+#else
FD_ZERO(&master_fds);
-
+#endif
for (i = 0; i < el->max_readers; i++) {
if (el->readers[i].fd < 0) continue;
FD_SET(el->readers[i].fd, &master_fds);
}
- el->changed = 0;
+ el->changed = false;
}
/*
read_fds = master_fds;
rcode = select(maxfd + 1, &read_fds, NULL, NULL, wake);
if ((rcode < 0) && (errno != EINTR)) {
- fr_strerror_printf("Failed in select: %s",
- strerror(errno));
- el->dispatch = 0;
+ fr_strerror_printf("Failed in select: %s", fr_syserror(errno));
+ el->dispatch = false;
return -1;
}
}
}
- el->dispatch = 0;
+ el->dispatch = false;
return el->exit;
}
struct timeval now, when;
fr_event_list_t *el;
- el = fr_event_list_create();
+ el = fr_event_list_create(NULL, NULL);
if (!el) exit(1);
memset(&rand_pool, 0, sizeof(rand_pool));
}
}
- fr_event_list_free(el);
+ talloc_free(el);
return 0;
}
token = fr_hex2bin(filter->value, argv[2], sizeof(filter->value));
if (token != sizeof(filter->value)) return -1;
- /*
- * The mask and value MUST be the same length.
- */
- if (rcode != token) return -1;
-
filter->len = rcode;
filter->len = htons(filter->len);
*
* return: -1 for error or 0.
*/
-int
-ascend_parse_filter(VALUE_PAIR *pair)
+int ascend_parse_filter(VALUE_PAIR *vp, char const *value, size_t len)
{
int token, type;
int rcode;
* Once the filter is *completelty* parsed, then we will
* over-write it with the final binary filter.
*/
- p = talloc_strdup(pair, pair->vp_strvalue);
+ p = talloc_memdup(vp, value, len);
+ p[len] = '\0';
argc = str2argv(p, argv, 32);
if (argc < 3) {
talloc_free(p);
fr_strerror_printf("Unknown Ascend filter direction \"%s\"", argv[1]);
talloc_free(p);
return -1;
- break;
}
/*
switch (type) {
case RAD_FILTER_GENERIC:
- rcode = ascend_parse_generic(argc - 3, &argv[3],
- &filter.u.generic);
+ rcode = ascend_parse_generic(argc - 3, &argv[3], &filter.u.generic);
break;
case RAD_FILTER_IP:
* Touch the VP only if everything was OK.
*/
if (rcode == 0) {
- pair->length = sizeof(filter);
- memcpy(pair->vp_filter, &filter, sizeof(filter));
+ vp->length = sizeof(filter);
+ memcpy(vp->vp_filter, &filter, sizeof(filter));
}
talloc_free(p);
* the previous 'more' to be valid. If any should fail then TURN OFF
* previous 'more'
*/
- if( prevRadPair ) {
- filt = ( RadFilter * )prevRadPair->vp_strvalue;
+ if( prevRadvp ) {
+ filt = ( RadFilter * )prevRadvp->vp_strvalue;
if(( tok != FILTER_GENERIC_TYPE ) || (rc == -1 ) ||
- ( prevRadPair->attribute != pair->attribute ) ||
+ ( prevRadvp->attribute != vp->attribute ) ||
( filt->indirection != radFil.indirection ) ||
( filt->forward != radFil.forward ) ) {
gen = &filt->u.generic;
valstr);
}
}
- prevRadPair = NULL;
+ prevRadvp = NULL;
if( rc != -1 && tok == FILTER_GENERIC_TYPE ) {
if( radFil.u.generic.more ) {
- prevRadPair = pair;
+ prevRadvp = vp;
}
}
if( rc != -1 ) {
- pairmemcpy(pair, &radFil, pair->length );
+ vpmemcpy(vp, &radFil, vp->length );
}
return(rc);
* Note we don't bother checking 'len' after the snprintf's.
* This function should ONLY be called with a large (~1k) buffer.
*/
-void print_abinary(VALUE_PAIR const *vp, char *buffer, size_t len, int8_t quote)
+void print_abinary(char *out, size_t outlen, VALUE_PAIR const *vp, int8_t quote)
{
- size_t i;
- char *p;
- ascend_filter_t *filter;
-
- static char const *action[] = {"drop", "forward"};
- static char const *direction[] = {"out", "in"};
-
- p = buffer;
-
- /*
- * Just for paranoia: wrong size filters get printed as octets
- */
- if (vp->length != sizeof(*filter)) {
- uint8_t *f = (uint8_t *) &vp->vp_filter;
- strcpy(p, "0x");
- p += 2;
- len -= 2;
- for (i = 0; i < vp->length; i++) {
- snprintf(p, len, "%02x", f[i]);
- p += 2;
- len -= 2;
- }
- return;
- }
-
- if (quote > 0) {
- *(p++) = (char) quote;
- len -= 3; /* account for leading & trailing quotes */
- }
-
- filter = (ascend_filter_t *) &(vp->vp_filter);
- i = snprintf(p, len, "%s %s %s",
- fr_int2str(filterType, filter->type, "??"),
- direction[filter->direction & 0x01],
- action[filter->forward & 0x01]);
-
- p += i;
- len -= i;
-
- /*
- * Handle IP filters
- */
- if (filter->type == RAD_FILTER_IP) {
-
- if (filter->u.ip.srcip) {
- i = snprintf(p, len, " srcip %d.%d.%d.%d/%d",
- ((uint8_t *) &filter->u.ip.srcip)[0],
- ((uint8_t *) &filter->u.ip.srcip)[1],
- ((uint8_t *) &filter->u.ip.srcip)[2],
- ((uint8_t *) &filter->u.ip.srcip)[3],
- filter->u.ip.srcmask);
- p += i;
- len -= i;
- }
+ size_t i;
+ char *p;
+ ascend_filter_t *filter;
- if (filter->u.ip.dstip) {
- i = snprintf(p, len, " dstip %d.%d.%d.%d/%d",
- ((uint8_t *) &filter->u.ip.dstip)[0],
- ((uint8_t *) &filter->u.ip.dstip)[1],
- ((uint8_t *) &filter->u.ip.dstip)[2],
- ((uint8_t *) &filter->u.ip.dstip)[3],
- filter->u.ip.dstmask);
- p += i;
- len -= i;
- }
+ static char const *action[] = {"drop", "forward"};
+ static char const *direction[] = {"out", "in"};
- i = snprintf(p, len, " %s",
- fr_int2str(filterProtoName, filter->u.ip.proto, "??"));
- p += i;
- len -= i;
-
- if (filter->u.ip.srcPortComp > RAD_NO_COMPARE) {
- i = snprintf(p, len, " srcport %s %d",
- fr_int2str(filterCompare, filter->u.ip.srcPortComp, "??"),
- ntohs(filter->u.ip.srcport));
- p += i;
- len -= i;
- }
+ p = out;
- if (filter->u.ip.dstPortComp > RAD_NO_COMPARE) {
- i = snprintf(p, len, " dstport %s %d",
- fr_int2str(filterCompare, filter->u.ip.dstPortComp, "??"),
- ntohs(filter->u.ip.dstport));
- p += i;
- len -= i;
- }
+ /*
+ * Just for paranoia: wrong size filters get printed as octets
+ */
+ if (vp->length != sizeof(*filter)) {
+ uint8_t *f = (uint8_t *) &vp->vp_filter;
+
+ strcpy(p, "0x");
+ p += 2;
+ outlen -= 2;
+ for (i = 0; i < vp->length; i++) {
+ snprintf(p, outlen, "%02x", f[i]);
+ p += 2;
+ outlen -= 2;
+ }
+ return;
+ }
- if (filter->u.ip.established) {
- i = snprintf(p, len, " est");
- p += i;
- }
+ if (quote > 0) {
+ *(p++) = (char) quote;
+ outlen -= 3; /* account for leading & trailing quotes */
+ }
- /*
- * Handle IPX filters
- */
- } else if (filter->type == RAD_FILTER_IPX) {
- /* print for source */
- if (filter->u.ipx.src.net) {
- i = snprintf(p, len, " srcipxnet 0x%04x srcipxnode 0x%02x%02x%02x%02x%02x%02x",
- (unsigned int)ntohl(filter->u.ipx.src.net),
- filter->u.ipx.src.node[0], filter->u.ipx.src.node[1],
- filter->u.ipx.src.node[2], filter->u.ipx.src.node[3],
- filter->u.ipx.src.node[4], filter->u.ipx.src.node[5]);
- p += i;
- len -= i;
-
- if (filter->u.ipx.srcSocComp > RAD_NO_COMPARE) {
- i = snprintf(p, len, " srcipxsock %s 0x%04x",
- fr_int2str(filterCompare, filter->u.ipx.srcSocComp, "??"),
- ntohs(filter->u.ipx.src.socket));
- p += i;
- len -= i;
- }
- }
+ filter = (ascend_filter_t *) &(vp->vp_filter);
+ i = snprintf(p, outlen, "%s %s %s", fr_int2str(filterType, filter->type, "??"),
+ direction[filter->direction & 0x01], action[filter->forward & 0x01]);
- /* same for destination */
- if (filter->u.ipx.dst.net) {
- i = snprintf(p, len, " dstipxnet 0x%04x dstipxnode 0x%02x%02x%02x%02x%02x%02x",
- (unsigned int)ntohl(filter->u.ipx.dst.net),
- filter->u.ipx.dst.node[0], filter->u.ipx.dst.node[1],
- filter->u.ipx.dst.node[2], filter->u.ipx.dst.node[3],
- filter->u.ipx.dst.node[4], filter->u.ipx.dst.node[5]);
- p += i;
- len -= i;
-
- if (filter->u.ipx.dstSocComp > RAD_NO_COMPARE) {
- i = snprintf(p, len, " dstipxsock %s 0x%04x",
- fr_int2str(filterCompare, filter->u.ipx.dstSocComp, "??"),
- ntohs(filter->u.ipx.dst.socket));
p += i;
- }
- }
+ outlen -= i;
+ /*
+ * Handle IP filters
+ */
+ if (filter->type == RAD_FILTER_IP) {
+
+ if (filter->u.ip.srcip) {
+ i = snprintf(p, outlen, " srcip %d.%d.%d.%d/%d",
+ ((uint8_t *) &filter->u.ip.srcip)[0],
+ ((uint8_t *) &filter->u.ip.srcip)[1],
+ ((uint8_t *) &filter->u.ip.srcip)[2],
+ ((uint8_t *) &filter->u.ip.srcip)[3],
+ filter->u.ip.srcmask);
+ p += i;
+ outlen -= i;
+ }
- } else if (filter->type == RAD_FILTER_GENERIC) {
- int count;
+ if (filter->u.ip.dstip) {
+ i = snprintf(p, outlen, " dstip %d.%d.%d.%d/%d",
+ ((uint8_t *) &filter->u.ip.dstip)[0],
+ ((uint8_t *) &filter->u.ip.dstip)[1],
+ ((uint8_t *) &filter->u.ip.dstip)[2],
+ ((uint8_t *) &filter->u.ip.dstip)[3],
+ filter->u.ip.dstmask);
+ p += i;
+ outlen -= i;
+ }
- i = snprintf(p, len, " %u ", (unsigned int) ntohs(filter->u.generic.offset));
- p += i;
+ i = snprintf(p, outlen, " %s", fr_int2str(filterProtoName, filter->u.ip.proto, "??"));
+ p += i;
+ outlen -= i;
- /* show the mask */
- for (count = 0; count < ntohs(filter->u.generic.len); count++) {
- i = snprintf(p, len, "%02x", filter->u.generic.mask[count]);
- p += i;
- len -= i;
- }
+ if (filter->u.ip.srcPortComp > RAD_NO_COMPARE) {
+ i = snprintf(p, outlen, " srcport %s %d",
+ fr_int2str(filterCompare, filter->u.ip.srcPortComp, "??"),
+ ntohs(filter->u.ip.srcport));
+ p += i;
+ outlen -= i;
+ }
- strcpy(p, " ");
- p++;
- len--;
+ if (filter->u.ip.dstPortComp > RAD_NO_COMPARE) {
+ i = snprintf(p, outlen, " dstport %s %d",
+ fr_int2str(filterCompare, filter->u.ip.dstPortComp, "??"),
+ ntohs(filter->u.ip.dstport));
+ p += i;
+ outlen -= i;
+ }
- /* show the value */
- for (count = 0; count < ntohs(filter->u.generic.len); count++) {
- i = snprintf(p, len, "%02x", filter->u.generic.value[count]);
- p += i;
- len -= i;
- }
+ if (filter->u.ip.established) {
+ i = snprintf(p, outlen, " est");
+ p += i;
+ }
+
+ /*
+ * Handle IPX filters
+ */
+ } else if (filter->type == RAD_FILTER_IPX) {
+ /* print for source */
+ if (filter->u.ipx.src.net) {
+ i = snprintf(p, outlen, " srcipxnet 0x%04x srcipxnode 0x%02x%02x%02x%02x%02x%02x",
+ (unsigned int)ntohl(filter->u.ipx.src.net),
+ filter->u.ipx.src.node[0], filter->u.ipx.src.node[1],
+ filter->u.ipx.src.node[2], filter->u.ipx.src.node[3],
+ filter->u.ipx.src.node[4], filter->u.ipx.src.node[5]);
+ p += i;
+ outlen -= i;
+
+ if (filter->u.ipx.srcSocComp > RAD_NO_COMPARE) {
+ i = snprintf(p, outlen, " srcipxsock %s 0x%04x",
+ fr_int2str(filterCompare, filter->u.ipx.srcSocComp, "??"),
+ ntohs(filter->u.ipx.src.socket));
+ p += i;
+ outlen -= i;
+ }
+ }
- i = snprintf(p, len, " %s", (filter->u.generic.compNeq) ? "!=" : "==");
- p += i;
- len -= i;
+ /* same for destination */
+ if (filter->u.ipx.dst.net) {
+ i = snprintf(p, outlen, " dstipxnet 0x%04x dstipxnode 0x%02x%02x%02x%02x%02x%02x",
+ (unsigned int)ntohl(filter->u.ipx.dst.net),
+ filter->u.ipx.dst.node[0], filter->u.ipx.dst.node[1],
+ filter->u.ipx.dst.node[2], filter->u.ipx.dst.node[3],
+ filter->u.ipx.dst.node[4], filter->u.ipx.dst.node[5]);
+ p += i;
+ outlen -= i;
+
+ if (filter->u.ipx.dstSocComp > RAD_NO_COMPARE) {
+ i = snprintf(p, outlen, " dstipxsock %s 0x%04x",
+ fr_int2str(filterCompare, filter->u.ipx.dstSocComp, "??"),
+ ntohs(filter->u.ipx.dst.socket));
+ p += i;
+ }
+ }
+ } else if (filter->type == RAD_FILTER_GENERIC) {
+ int count;
- if (filter->u.generic.more != 0) {
- i = snprintf(p, len, " more");
- p += i;
- }
- }
+ i = snprintf(p, outlen, " %u ", (unsigned int) ntohs(filter->u.generic.offset));
+ p += i;
- if (quote > 0) *(p++) = (char) quote;
- *p = '\0';
+ /* show the mask */
+ for (count = 0; count < ntohs(filter->u.generic.len); count++) {
+ i = snprintf(p, outlen, "%02x", filter->u.generic.mask[count]);
+ p += i;
+ outlen -= i;
+ }
+
+ strcpy(p, " ");
+ p++;
+ outlen--;
+
+ /* show the value */
+ for (count = 0; count < ntohs(filter->u.generic.len); count++) {
+ i = snprintf(p, outlen, "%02x", filter->u.generic.value[count]);
+ p += i;
+ outlen -= i;
+ }
+
+ i = snprintf(p, outlen, " %s", (filter->u.generic.compNeq) ? "!=" : "==");
+ p += i;
+ outlen -= i;
+
+ if (filter->u.generic.more != 0) {
+ i = snprintf(p, outlen, " more");
+ p += i;
+ }
+ }
+
+ if (quote > 0) {
+ *(p++) = (char) quote;
+ }
+ *p = '\0';
}
+
#endif
#ifdef HAVE_PTHREAD_H
if (fr_hostbyname == 0) {
- pthread_mutex_init(&fr_hostbyname_mutex, NULL);
+ pthread_mutex_init(&fr_hostbyname_mutex, NULL);
fr_hostbyname = 1;
}
pthread_mutex_lock(&fr_hostbyname_mutex);
#ifdef HAVE_PTHREAD_H
if (fr_hostbyaddr == 0) {
- pthread_mutex_init(&fr_hostbyaddr_mutex, NULL);
+ pthread_mutex_init(&fr_hostbyaddr_mutex, NULL);
fr_hostbyaddr = 1;
}
pthread_mutex_lock(&fr_hostbyaddr_mutex);
#ifndef HAVE_GETADDRINFO
static struct addrinfo *
-malloc_ai(int port, u_long addr, int socktype, int proto)
+malloc_ai(uint16_t port, u_long addr, int socktype, int proto)
{
struct addrinfo *ai;
struct hostent *hp;
struct hostent result;
struct in_addr in;
- int i, port = 0, socktype, proto;
+ int i, socktype, proto;
+ uint16_t port = 0;
int error;
char buffer[2048];
struct fr_hash_entry_t *next;
uint32_t reversed;
uint32_t key;
- void const *data;
+ void const *data;
} fr_hash_entry_t;
next = node->next;
- memcpy(&arg, node->data, sizeof(arg));
+ memcpy(&arg, &node->data, sizeof(arg));
rcode = callback(context, arg);
if (rcode != 0) return rcode;
}
/*
- * Return a "folded" hash, where the lower "bits" are the
- * hash, and the upper bits are zero.
- *
- * If you need a non-power-of-two hash, cope.
- */
-uint32_t fr_hash_fold(uint32_t hash, int bits)
-{
- int count;
- uint32_t result;
-
- if ((bits <= 0) || (bits >= 32)) return hash;
-
- result = hash;
-
- /*
- * Never use the same bits twice in an xor.
- */
- for (count = 0; count < 32; count += bits) {
- hash >>= bits;
- result ^= hash;
- }
-
- return result & (((uint32_t) (1 << bits)) - 1);
-}
-
-
-/*
* Hash a C string, so we loop over it once.
*/
uint32_t fr_hash_string(char const *p)
#ifdef TESTING
+static bool fr_heap_check(fr_heap_t *hp, void *data)
+{
+ int i;
+
+ if (!hp || (hp->num_elements == 0)) return false;
+
+ for (i = 0; i < hp->num_elements; i++) {
+ if (hp->p[i] == data) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+typedef struct heap_thing {
+ int data;
+ int heap; /* for the heap */
+} heap_thing;
+
+
/*
* cc -g -DTESTING -I .. heap.c -o heap
*
* ./heap
*/
-static int heap_cmp(void const *a, void const *b)
+static int heap_cmp(void const *one, void const *two)
{
- return *(int *)a - *(int *) b;
+ heap_thing const *a;
+ heap_thing const *b;
+
+ a = (heap_thing const *) one;
+ b = (heap_thing const *) two;
+
+ return a->data - b->data;
}
+#define ARRAY_SIZE (1024)
-int main(int argc, char **arg)
+void NEVER_RETURNS _fr_exit(char const *file, int line, int status)
+{
+#ifndef NDEBUG
+ fprintf(stderr, "EXIT CALLED %s[%u]: %i: ", file, line, status);
+#endif
+ fflush(stderr);
+ exit(status);
+}
+
+int main(int argc, char **argv)
{
fr_heap_t *hp;
- int i, array[1024];
+ int i;
+ heap_thing array[ARRAY_SIZE];
+ int skip = 0;
+ int left;
+
+ if (argc > 1) {
+ skip = atoi(argv[1]);
+ }
- hp = fr_heap_create(heap_cmp, 0);
+ hp = fr_heap_create(heap_cmp, offsetof(heap_thing, heap));
if (!hp) {
fprintf(stderr, "Failed creating heap!\n");
fr_exit(1);
}
- for (i = 0; i < 1024; i++) {
- array[i] = (i * 257) % 65537;
+ for (i = 0; i < ARRAY_SIZE; i++) {
+ array[i].data = rand() % 65537;
if (!fr_heap_insert(hp, &array[i])) {
fprintf(stderr, "Failed inserting %d\n", i);
fr_exit(1);
}
+
+ if (!fr_heap_check(hp, &array[i])) {
+ fprintf(stderr, "Inserted but not in heap %d\n", i);
+ fr_exit(1);
+ }
}
- for (i = 0; i < 1024; i++) {
- int *p = fr_heap_peek(hp);
+#if 0
+ for (i = 0; i < ARRAY_SIZE; i++) {
+ printf("Array %d has value %d at offset %d\n",
+ i, array[i].data, array[i].heap);
+ }
+#endif
+
+ if (skip) {
+ int entry;
+
+ printf("%d elements to remove\n", ARRAY_SIZE / skip);
+
+ for (i = 0; i < ARRAY_SIZE / skip; i++) {
+ entry = i * skip;
+
+ if (!fr_heap_extract(hp, &array[entry])) {
+ fprintf(stderr, "Failed removing %d\n", entry);
+ }
+
+ if (fr_heap_check(hp, &array[entry])) {
+ fprintf(stderr, "Deleted but still in heap %d\n", entry);
+ fr_exit(1);
+ }
- if (!p) {
+ if (array[entry].heap != -1) {
+ fprintf(stderr, "heap offset is wrong %d\n", entry);
+ fr_exit(1);
+ }
+ }
+ }
+
+ left = fr_heap_num_elements(hp);
+ printf("%d elements left in the heap\n", left);
+
+ for (i = 0; i < left; i++) {
+ heap_thing *t = fr_heap_peek(hp);
+
+ if (!t) {
fprintf(stderr, "Failed peeking %d\n", i);
fr_exit(1);
}
- printf("%d\t%d\n", i, *p);
+ printf("%d\t%d\n", i, t->data);
if (!fr_heap_extract(hp, NULL)) {
fprintf(stderr, "Failed extracting %d\n", i);
}
}
+ if (fr_heap_num_elements(hp) > 0) {
+ fprintf(stderr, "%d elements left at the end", fr_heap_num_elements(hp));
+ fr_exit(1);
+ }
+
fr_heap_delete(hp);
return 0;
#include <freeradius-devel/libradius.h>
-
-#define FR_STRERROR_BUFSIZE (1024)
-
-#ifdef HAVE_THREAD_TLS
/*
- * GCC on most Linux systems
+ * Are we using glibc or a close relative?
*/
-#define THREAD_TLS __thread
+#ifdef HAVE_FEATURES_H
+# include <features.h>
+#endif
-#elif defined(HAVE_DECLSPEC_THREAD)
-/*
- * Visual C++, Borland
- */
-#define THREAD_TLS __declspec(thread)
-#else
+#define FR_STRERROR_BUFSIZE (2048)
-/*
- * We don't have thread-local storage. Ensure we don't
- * ask for it.
- */
-#define THREAD_TLS
+fr_thread_local_setup(char *, fr_strerror_buffer) /* macro */
+fr_thread_local_setup(char *, fr_syserror_buffer) /* macro */
-/*
- * Use pthread keys if we have pthreads. For MAC, which should
- * be very fast.
- */
-#ifdef HAVE_PTHREAD_H
-#define USE_PTHREAD_FOR_TLS (1)
-#endif
-#endif
-#ifndef USE_PTHREAD_FOR_TLS
/*
- * Try to create a thread-local-storage version of this buffer.
+ * Explicitly cleanup the memory allocated to the error buffer,
+ * just in case valgrind complains about it.
*/
-static THREAD_TLS char fr_strerror_buffer[FR_STRERROR_BUFSIZE];
-
-#else
-#include <pthread.h>
-
-static pthread_key_t fr_strerror_key;
-static pthread_once_t fr_strerror_once = PTHREAD_ONCE_INIT;
-
-/* Create Key */
-static void fr_strerror_make_key(void)
+static void _fr_logging_free(void *arg)
{
- pthread_key_create(&fr_strerror_key, NULL);
+ free(arg);
}
-#endif
-/*
- * Log to a buffer, trying to be thread-safe.
+/** Log to thread local error buffer
+ *
+ * @param fmt printf style format string. If NULL sets the 'new' byte to false,
+ * effectively clearing the last message.
*/
void fr_strerror_printf(char const *fmt, ...)
{
va_list ap;
-#ifdef USE_PTHREAD_FOR_TLS
char *buffer;
- pthread_once(&fr_strerror_once, fr_strerror_make_key);
-
- buffer = pthread_getspecific(fr_strerror_key);
+ buffer = fr_thread_local_init(fr_strerror_buffer, _fr_logging_free);
if (!buffer) {
int ret;
- buffer = malloc(FR_STRERROR_BUFSIZE);
- if (!buffer) return; /* panic and die! */
+ /*
+ * malloc is thread safe, talloc is not
+ */
+ buffer = malloc(sizeof(char) * (FR_STRERROR_BUFSIZE + 1)); /* One byte extra for status */
+ if (!buffer) {
+ fr_perror("Failed allocating memory for libradius error buffer");
+ return;
+ }
- ret = pthread_setspecific(fr_strerror_key, buffer);
+ ret = fr_thread_local_set(fr_strerror_buffer, buffer);
if (ret != 0) {
- fr_perror("Failed recording thread error: %s",
- strerror(ret));
-
+ fr_perror("Failed setting up TLS for libradius error buffer: %s", fr_syserror(ret));
+ free(buffer);
return;
}
}
- va_start(ap, fmt);
- vsnprintf(buffer, FR_STRERROR_BUFSIZE, fmt, ap);
+ /*
+ * NULL has a special meaning, setting the new byte to false.
+ */
+ if (!fmt) {
+ buffer[FR_STRERROR_BUFSIZE] = '\0';
+ return;
+ }
-#else
va_start(ap, fmt);
- vsnprintf(fr_strerror_buffer, sizeof(fr_strerror_buffer), fmt, ap);
-#endif
-
+ vsnprintf(buffer, FR_STRERROR_BUFSIZE, fmt, ap);
+ buffer[FR_STRERROR_BUFSIZE] = '\1'; /* Flip the 'new' byte to true */
va_end(ap);
}
+/** Get the last library error
+ *
+ * Will only return the last library error once, after which it will return a zero length string.
+ *
+ * @return library error or zero length string
+ */
char const *fr_strerror(void)
{
-#ifndef USE_PTHREAD_FOR_TLS
- return fr_strerror_buffer;
+ char *buffer;
-#else
- char const *msg;
+ buffer = fr_thread_local_get(fr_strerror_buffer);
+ if (buffer && (buffer[FR_STRERROR_BUFSIZE] != '\0')) {
+ buffer[FR_STRERROR_BUFSIZE] = '\0'; /* Flip the 'new' byte to false */
+ return buffer;
+ }
+
+ return "";
+}
+
+/** Guaranteed to be thread-safe version of strerror
+ *
+ * @param num errno as returned by function or from global errno.
+ * @return local specific error string relating to errno.
+ */
+char const *fr_syserror(int num)
+{
+ char *buffer;
+ int ret;
- pthread_once(&fr_strerror_once, fr_strerror_make_key);
+ buffer = fr_thread_local_init(fr_syserror_buffer, _fr_logging_free);
+ if (!buffer) {
+ /*
+ * malloc is thread safe, talloc is not
+ */
+ buffer = malloc(sizeof(char) * FR_STRERROR_BUFSIZE);
+ if (!buffer) {
+ fr_perror("Failed allocating memory for system error buffer");
+ return NULL;
+ }
- msg = pthread_getspecific(fr_strerror_key);
- if (msg) return msg;
+ ret = fr_thread_local_set(fr_syserror_buffer, buffer);
+ if (ret != 0) {
+ fr_perror("Failed setting up TLS for system error buffer: %s", fr_syserror(ret));
+ free(buffer);
+ return NULL;
+ }
+ }
- return "(unknown error)"; /* DON'T return NULL! */
+ if (!num) {
+ return "No error";
+ }
+
+ /*
+ * XSI-Compliant version
+ */
+#if !defined(HAVE_FEATURES_H) || ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 500) && ! _GNU_SOURCE)
+ if ((ret = strerror_r(num, buffer, (size_t) FR_STRERROR_BUFSIZE) != 0)) {
+# ifndef NDEBUG
+ fprintf(stderr, "strerror_r() failed to write error for errno %i to buffer %p (%zu bytes), "
+ "returned %i: %s\n", num, buffer, (size_t) FR_STRERROR_BUFSIZE, ret, strerror(ret));
+# endif
+ buffer[0] = '\0';
+ }
+ return buffer;
+ /*
+ * GNU Specific version
+ *
+ * The GNU Specific version returns a char pointer. That pointer may point
+ * the buffer you just passed in, or to an immutable static string.
+ */
+#else
+ {
+ char const *p;
+ p = strerror_r(num, buffer, (size_t) FR_STRERROR_BUFSIZE);
+ if (!p) {
+# ifndef NDEBUG
+ fprintf(stderr, "strerror_r() failed to write error for errno %i to buffer %p "
+ "(%zu bytes): %s\n", num, buffer, (size_t) FR_STRERROR_BUFSIZE, strerror(errno));
+# endif
+ buffer[0] = '\0';
+ return buffer;
+ }
+ return p;
+ }
#endif
+
}
void fr_perror(char const *fmt, ...)
{
+ char const *error;
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
- if (strchr(fmt, ':') == NULL)
- fprintf(stderr, ": ");
- fprintf(stderr, "%s\n", fr_strerror());
+
+ error = fr_strerror();
+ if (error && (error[0] != '\0')) {
+ fprintf(stderr, ": %s\n", error);
+ } else {
+ fputs("\n", stderr);
+ }
+
va_end(ap);
}
{
if (!cond) {
fr_perror("SOFT ASSERT FAILED %s[%u]: %s", file, line, expr);
+#if !defined(NDEBUG) && defined(SIGUSR1)
+ fr_fault(SIGUSR1);
+#endif
return false;
}
void NEVER_RETURNS _fr_exit(char const *file, int line, int status)
{
#ifndef NDEBUG
- fr_perror("EXIT CALLED %s[%u]: %i", file, line, status);
+ char const *error = fr_strerror();
+
+ if (error && (status != 0)) {
+ fr_perror("EXIT(%i) CALLED %s[%u]. Last error was: %s", status, file, line, error);
+ } else {
+ fr_perror("EXIT(%i) CALLED %s[%u]", status, file, line);
+ }
#endif
+ fr_perror("If running under a debugger it should break <<here>>");
fflush(stderr);
fr_debug_break(); /* If running under GDB we'll break here */
void NEVER_RETURNS _fr_exit_now(char const *file, int line, int status)
{
#ifndef NDEBUG
- fr_perror("_EXIT CALLED %s[%u]: %i", file, line, status);
+ char const *error = fr_strerror();
+
+ if (error && (status != 0)) {
+ fr_perror("_EXIT(%i) CALLED %s[%u]. Last error was: %s", status, file, line, error);
+ } else {
+ fr_perror("_EXIT(%i) CALLED %s[%u]", status, file, line);
+ }
#endif
+ fr_perror("If running under a debugger it should break <<here>>");
fflush(stderr);
fr_debug_break(); /* If running under GDB we'll break here */
* FORCE MD4 TO USE OUR MD4 HEADER FILE!
* If we don't do this, it might pick up the systems broken MD4.
*/
-#include "../include/md4.h"
+#include <freeradius-devel/md4.h>
void fr_md4_calc(output, input, inlen)
unsigned char *output;
fr_MD4Final(output, &context);
}
-#ifndef WITH_OPENSSL_MD4
+#ifndef HAVE_OPENSSL_MD4_H
/* The below was retrieved from
* http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/lib/libc/hash/md4.c?rev=1.2
* with the following changes:
* FORCE MD5 TO USE OUR MD5 HEADER FILE!
* If we don't do this, it might pick up the systems broken MD5.
*/
-#include "../include/md5.h"
+#include <freeradius-devel/md5.h>
void fr_md5_calc(uint8_t *output, uint8_t const *input,
unsigned int inlen)
}
-#ifndef WITH_OPENSSL_MD5
+#ifndef HAVE_OPENSSL_MD5_H
/* The below was retrieved from
* http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/crypto/md5.c?rev=1.1
* with the following changes:
memset(ctx, 0, sizeof(*ctx)); /* in case it's sensitive */
}
-
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#include <ctype.h>
#include <sys/file.h>
#include <fcntl.h>
-#include <signal.h>
#define FR_PUT_LE16(a, val)\
do {\
a[0] = ((uint16_t) (val)) & 0xff;\
} while (0)
-static int fr_debugger_present = -1;
+#ifdef HAVE_PTHREAD_H
+static pthread_mutex_t autofree_context = PTHREAD_MUTEX_INITIALIZER;
+# define PTHREAD_MUTEX_LOCK pthread_mutex_lock
+# define PTHREAD_MUTEX_UNLOCK pthread_mutex_unlock
+#else
+# define PTHREAD_MUTEX_LOCK(_x)
+# define PTHREAD_MUTEX_UNLOCK(_x)
+#endif
bool fr_dns_lookups = false; /* IP -> hostname lookups? */
bool fr_hostname_lookups = true; /* hostname -> IP lookups? */
"jan", "feb", "mar", "apr", "may", "jun",
"jul", "aug", "sep", "oct", "nov", "dec" };
+fr_thread_local_setup(char *, fr_inet_ntop_buffer); /* macro */
+
+/** 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, fr_syserror(errno));
+ return -1;
+ }
+#else
+ if (signal(sig, func) < 0) {
+ fr_strerror_printf("Failed setting signal %i handler via signal(): %s", sig, fr_syserror(errno));
+ return -1;
+ }
+#endif
+ return 0;
+}
+
/** Allocates a new talloc context from the root autofree context
*
- * @param signum signal raised.
+ * This function is threadsafe, whereas using the NULL context is not.
+ *
+ * @note The returned context must be freed by the caller.
+ * @returns a new talloc context parented by the root autofree context.
*/
-static void _sigtrap_handler(UNUSED int signum)
+TALLOC_CTX *fr_autofree_ctx(void)
{
- fr_debugger_present = 0;
- signal(SIGTRAP, SIG_DFL);
+ static TALLOC_CTX *ctx = NULL, *child;
+ PTHREAD_MUTEX_LOCK(&autofree_context);
+ if (!ctx) {
+ ctx = talloc_autofree_context();
+ }
+
+ child = talloc_new(ctx);
+ PTHREAD_MUTEX_UNLOCK(&autofree_context);
+
+ return child;
}
-/** Break in GDB (if were running under GDB)
+/*
+ * Explicitly cleanup the memory allocated to the error inet_ntop
+ * buffer.
+ */
+static void _fr_inet_ntop_free(void *arg)
+{
+ free(arg);
+}
+
+/** Wrapper around inet_ntop, prints IPv4/IPv6 addresses
+ *
+ * inet_ntop requires the caller pass in a buffer for the address.
+ * This would be annoying and cumbersome, seeing as quite often the ASCII
+ * address is only used for logging output.
*
- * If the server is running under GDB this will raise a SIGTRAP which
- * will pause the running process.
+ * So as with lib/log.c use TLS to allocate thread specific buffers, and
+ * write the IP address there instead.
*
- * If the server is not running under GDB then this will do nothing.
+ * @param af address family, either AF_INET or AF_INET6.
+ * @param src pointer to network address structure.
+ * @return NULL on error, else pointer to ASCII buffer containing text version of address.
*/
-void fr_debug_break(void)
+char const *fr_inet_ntop(int af, void const *src)
{
- if (fr_debugger_present == -1) {
- fr_debugger_present = 0;
- signal(SIGTRAP, _sigtrap_handler);
- raise(SIGTRAP);
- } else if (fr_debugger_present == 1) {
- raise(SIGTRAP);
- }
+ char *buffer;
+
+ if (!src) {
+ return NULL;
+ }
+
+ buffer = fr_thread_local_init(fr_inet_ntop_buffer, _fr_inet_ntop_free);
+ if (!buffer) {
+ int ret;
+
+ /*
+ * malloc is thread safe, talloc is not
+ */
+ buffer = malloc(sizeof(char) * INET6_ADDRSTRLEN);
+ if (!buffer) {
+ fr_perror("Failed allocating memory for inet_ntop buffer");
+ return NULL;
+ }
+
+ ret = fr_thread_local_set(fr_inet_ntop_buffer, buffer);
+ if (ret != 0) {
+ fr_perror("Failed setting up TLS for inet_ntop buffer: %s", fr_syserror(ret));
+ free(buffer);
+ return NULL;
+ }
+ }
+ buffer[0] = '\0';
+
+ return inet_ntop(af, src, buffer, INET6_ADDRSTRLEN);
}
/*
return buffer;
}
+/** Parse an IPv4 address or IPv4 prefix in presentation format (and others)
+ *
+ * @param out Where to write the ip address value.
+ * @param value to parse, may be dotted quad [+ prefix], or integer, or octal number, or '*' (INADDR_ANY).
+ * @param inlen Length of value, if value is \0 terminated inlen may be 0.
+ * @param resolve If true and value doesn't look like an IP address, try and resolve value as a hostname.
+ * @param fallback to IPv4 resolution if no A records can be found.
+ * @return 0 if ip address was parsed successfully, else -1 on error.
+ */
+int fr_pton4(fr_ipaddr_t *out, char const *value, size_t inlen, bool resolve, bool fallback)
+{
+ char *p;
+ unsigned int prefix;
+ char *eptr;
+
+ /* Dotted quad + / + [0-9]{1,2} */
+ char buffer[INET_ADDRSTRLEN + 3];
+
+ /*
+ * Copy to intermediary buffer if we were given a length
+ */
+ if (inlen > 0) {
+ if (inlen >= sizeof(buffer)) {
+ fr_strerror_printf("Invalid IPv4 address string \"%s\"", value);
+ return -1;
+ }
+ memcpy(buffer, value, inlen);
+ buffer[inlen] = '\0';
+ }
+
+ p = strchr(value, '/');
+ /*
+ * 192.0.2.2 is parsed as if it was /32
+ */
+ if (!p) {
+ /*
+ * Allow '*' as the wildcard address usually 0.0.0.0
+ */
+ if ((value[0] == '*') && (value[1] == '\0')) {
+ out->ipaddr.ip4addr.s_addr = htonl(INADDR_ANY);
+ /*
+ * Convert things which are obviously integers to IP addresses
+ *
+ * We assume the number is the bigendian representation of the
+ * IP address.
+ */
+ } else if (is_integer(value)) {
+ out->ipaddr.ip4addr.s_addr = htonl(strtoul(value, NULL, 0));
+ } else if (!resolve) {
+ if (inet_pton(AF_INET, value, &(out->ipaddr.ip4addr.s_addr)) <= 0) {
+ fr_strerror_printf("Failed to parse IPv4 address string \"%s\"", value);
+ return -1;
+ }
+ } else if (ip_hton(out, AF_INET, value, fallback) < 0) return -1;
+
+ out->prefix = 32;
+ out->af = AF_INET;
+
+ return 0;
+ }
+
+ /*
+ * Otherwise parse the prefix
+ */
+ if ((size_t)(p - value) >= INET_ADDRSTRLEN) {
+ fr_strerror_printf("Invalid IPv4 address string \"%s\"", value);
+ return -1;
+ }
+
+ /*
+ * Copy the IP portion into a temporary buffer if we haven't already.
+ */
+ if (inlen == 0) memcpy(buffer, value, p - value);
+ buffer[p - value] = '\0';
+
+ if (!resolve) {
+ if (inet_pton(AF_INET, buffer, &(out->ipaddr.ip4addr.s_addr)) <= 0) {
+ fr_strerror_printf("Failed to parse IPv4 address string \"%s\"", value);
+ return -1;
+ }
+ } else if (ip_hton(out, AF_INET, buffer, fallback) < 0) return -1;
+
+ prefix = strtoul(p + 1, &eptr, 10);
+ if (prefix > 32) {
+ fr_strerror_printf("Invalid IPv4 mask length \"%s\". Should be between 0-32", p);
+ return -1;
+ }
+ if (eptr[0] != '\0') {
+ fr_strerror_printf("Failed to parse IPv4 address string \"%s\", "
+ "got garbage after mask length \"%s\"", value, eptr);
+ return -1;
+ }
+
+ if (prefix < 32) {
+ out->ipaddr.ip4addr = fr_inaddr_mask(&(out->ipaddr.ip4addr), prefix);
+ }
+
+ out->prefix = (uint8_t) prefix;
+ out->af = AF_INET;
+
+ return 0;
+}
+
+/** Parse an IPv6 address or IPv6 prefix in presentation format (and others)
+ *
+ * @param out Where to write the ip address value.
+ * @param value to parse.
+ * @param inlen Length of value, if value is \0 terminated inlen may be 0.
+ * @param resolve If true and value doesn't look like an IP address, try and resolve value as a hostname.
+ * @param fallback to IPv4 resolution if no AAAA records can be found.
+ * @return 0 if ip address was parsed successfully, else -1 on error.
+ */
+int fr_pton6(fr_ipaddr_t *out, char const *value, size_t inlen, bool resolve, bool fallback)
+{
+ char const *p;
+ unsigned int prefix;
+ char *eptr;
+
+ /* IPv6 + / + [0-9]{1,3} */
+ char buffer[INET6_ADDRSTRLEN + 4];
+
+ /*
+ * Copy to intermediary buffer if we were given a length
+ */
+ if (inlen > 0) {
+ if (inlen >= sizeof(buffer)) {
+ fr_strerror_printf("Invalid IPv6 address string \"%s\"", value);
+ return -1;
+ }
+ memcpy(buffer, value, inlen);
+ buffer[inlen] = '\0';
+ }
+
+ p = strchr(value, '/');
+ if (!p) {
+ /*
+ * Allow '*' as the wildcard address
+ */
+ if ((value[0] == '*') && (value[1] == '\0')) {
+ memset(&out->ipaddr.ip6addr.s6_addr, 0, sizeof(out->ipaddr.ip6addr.s6_addr));
+ } else if (!resolve) {
+ if (inet_pton(AF_INET6, value, &(out->ipaddr.ip6addr.s6_addr)) <= 0) {
+ fr_strerror_printf("Failed to parse IPv6 address string \"%s\"", value);
+ return -1;
+ }
+ } else if (ip_hton(out, AF_INET6, value, fallback) < 0) return -1;
+
+ out->prefix = 128;
+ out->af = AF_INET6;
+
+ return 0;
+ }
+
+ if ((p - value) >= INET6_ADDRSTRLEN) {
+ fr_strerror_printf("Invalid IPv6 address string \"%s\"", value);
+ return -1;
+ }
+
+ /*
+ * Copy string to temporary buffer if we didn't do it earlier
+ */
+ if (inlen == 0) memcpy(buffer, value, p - value);
+ buffer[p - value] = '\0';
+
+ if (!resolve) {
+ if (inet_pton(AF_INET6, buffer, &(out->ipaddr.ip6addr.s6_addr)) <= 0) {
+ fr_strerror_printf("Failed to parse IPv6 address string \"%s\"", value);
+ return -1;
+ }
+ } else if (ip_hton(out, AF_INET6, buffer, fallback) < 0) return -1;
+
+ prefix = strtoul(p + 1, &eptr, 10);
+ if (prefix > 128) {
+ fr_strerror_printf("Invalid IPv6 mask length \"%s\". Should be between 0-128", p);
+ return -1;
+ }
+ if (eptr[0] != '\0') {
+ fr_strerror_printf("Failed to parse IPv6 address string \"%s\", "
+ "got garbage after mask length \"%s\"", value, eptr);
+ return -1;
+ }
+
+ if (prefix < 128) {
+ struct in6_addr addr;
+
+ addr = fr_in6addr_mask(&(out->ipaddr.ip6addr), prefix);
+ memcpy(&(out->ipaddr.ip6addr.s6_addr), &addr, sizeof(addr));
+ }
+
+ out->prefix = (uint8_t) prefix;
+ out->af = AF_INET6;
+
+ return 0;
+}
+
+/** Simple wrapper to decide whether an IP value is v4 or v6 and call the appropriate parser.
+ *
+ * @param out Where to write the ip address value.
+ * @param value to parse.
+ * @param inlen Length of value, if value is \0 terminated inlen may be 0.
+ * @param resolve If true and value doesn't look like an IP address, try and resolve value as a hostname.
+ * @return 0 if ip address was parsed successfully, else -1 on error.
+ */
+int fr_pton(fr_ipaddr_t *out, char const *value, size_t inlen, bool resolve)
+{
+ size_t len, i;
+
+ len = (inlen == 0) ? strlen(value) : inlen;
+ for (i = 0; i < len; i++) switch (value[i]) {
+ /*
+ * Chars illegal in domain names and IPv4 addresses.
+ * Must be v6 and cannot be a domain.
+ */
+ case ':':
+ case '[':
+ case ']':
+ return fr_pton6(out, value, inlen, false, false);
+
+ /*
+ * Chars which don't really tell us anything
+ */
+ case '.':
+ case '/':
+ continue;
+
+ default:
+ /*
+ * Outside the range of IPv4 chars, must be a domain
+ * Use A record in preference to AAAA record.
+ */
+ if ((value[i] < '0') || (value[i] > '9')) {
+ if (!resolve) return -1;
+ return fr_pton4(out, value, inlen, true, true);
+ }
+ break;
+ }
+
+ /*
+ * All chars were in the IPv4 set [0-9/.], must be an IPv4
+ * address.
+ */
+ return fr_pton4(out, value, inlen, false, false);
+}
+
+/** Check if the IP address is equivalent to INADDR_ANY
+ *
+ * @param addr to chec.
+ * @return true if IP address matches INADDR_ANY or INADDR6_ANY (assumed to be 0), else false.
+ */
+bool is_wildcard(fr_ipaddr_t *addr)
+{
+ static struct in6_addr in6_addr;
+
+ switch (addr->af) {
+ case AF_INET:
+ return (addr->ipaddr.ip4addr.s_addr == htons(INADDR_ANY));
+
+ case AF_INET6:
+ return (memcmp(addr->ipaddr.ip6addr.s6_addr, in6_addr.s6_addr, sizeof(in6_addr.s6_addr)) == 0) ? true :false;
+
+ default:
+ fr_assert(0);
+ return false;
+ }
+}
+
+int fr_ntop(char *out, size_t outlen, fr_ipaddr_t *addr)
+{
+ char buffer[INET6_ADDRSTRLEN];
+
+ if (inet_ntop(addr->af, &(addr->ipaddr), buffer, sizeof(buffer)) == NULL) return -1;
+
+ return snprintf(out, outlen, "%s/%i", buffer, addr->prefix);
+}
+
/*
* Internal wrapper for locking, to minimize the number of ifdef's
*
* in missing.h
*/
if (af == AF_INET6) {
- struct const in6_addr *ipaddr = src;
+ struct in6_addr const *ipaddr = src;
if (cnt <= INET6_ADDRSTRLEN) return NULL;
}
#endif
-
-/*
- * Try to convert the address to v4 then v6
- */
-int ip_ptonx(char const *src, fr_ipaddr_t *dst)
-{
- if (inet_pton(AF_INET, src, &dst->ipaddr.ip4addr) == 1) {
- dst->af = AF_INET;
- return 1;
- }
-
-#ifdef HAVE_STRUCT_SOCKADDR_IN6
- if (inet_pton(AF_INET6, src, &dst->ipaddr.ip6addr) == 1) {
- dst->af = AF_INET6;
- return 1;
- }
-#endif
-
- return 0;
-}
-
-/*
- * Wrappers for IPv4/IPv6 host to IP address lookup.
- * This API returns only one IP address, of the specified
- * address family, or the first address (of whatever family),
- * if AF_UNSPEC is used.
+/** Wrappers for IPv4/IPv6 host to IP address lookup
+ *
+ * This function returns only one IP address, of the specified address family,
+ * or the first address (of whatever family), if AF_UNSPEC is used.
+ *
+ * If fallback is specified and af is AF_INET, but no AF_INET records were
+ * found and a record for AF_INET6 exists that record will be returned.
+ *
+ * If fallback is specified and af is AF_INET6, and a record with AF_INET4 exists
+ * that record will be returned instead.
+ *
+ * @param out Where to write result.
+ * @param af To search for in preference.
+ * @param hostname to search for.
+ * @param fallback to the other adress family, if no records matching af, found.
+ * @return 0 on success, else -1 on failure.
*/
-int ip_hton(char const *src, int af, fr_ipaddr_t *dst)
+int ip_hton(fr_ipaddr_t *out, int af, char const *hostname, bool fallback)
{
int rcode;
- struct addrinfo hints, *ai = NULL, *res = NULL;
+ struct addrinfo hints, *ai = NULL, *alt = NULL, *res = NULL;
if (!fr_hostname_lookups) {
#ifdef HAVE_STRUCT_SOCKADDR_IN6
if (af == AF_UNSPEC) {
char const *p;
- for (p = src; *p != '\0'; p++) {
+ for (p = hostname; *p != '\0'; p++) {
if ((*p == ':') ||
(*p == '[') ||
(*p == ']')) {
if (af == AF_UNSPEC) af = AF_INET;
- if (!inet_pton(af, src, &(dst->ipaddr))) {
+ if (!inet_pton(af, hostname, &(out->ipaddr))) {
return -1;
}
-
- dst->af = af;
+
+ out->af = af;
return 0;
}
/*
* If it's all numeric, avoid getaddrinfo()
*/
- if (inet_pton(af, src, &dst->ipaddr.ip4addr) == 1) {
+ if (inet_pton(af, hostname, &out->ipaddr.ip4addr) == 1) {
return 0;
}
}
#endif
- if ((rcode = getaddrinfo(src, NULL, &hints, &res)) != 0) {
+ if ((rcode = getaddrinfo(hostname, NULL, &hints, &res)) != 0) {
fr_strerror_printf("ip_hton: %s", gai_strerror(rcode));
return -1;
}
for (ai = res; ai; ai = ai->ai_next) {
- if ((af == ai->ai_family) || (af == AF_UNSPEC))
- break;
+ if ((af == ai->ai_family) || (af == AF_UNSPEC)) break;
+ if (!alt && fallback && ((ai->ai_family == AF_INET) || (ai->ai_family == AF_INET6))) alt = ai;
}
+ if (!ai) ai = alt;
if (!ai) {
- fr_strerror_printf("ip_hton failed to find requested information for host %.100s", src);
+ fr_strerror_printf("ip_hton failed to find requested information for host %.100s", hostname);
freeaddrinfo(ai);
return -1;
}
rcode = fr_sockaddr2ipaddr((struct sockaddr_storage *)ai->ai_addr,
- ai->ai_addrlen, dst, NULL);
+ ai->ai_addrlen, out, NULL);
freeaddrinfo(ai);
if (!rcode) return -1;
return dst;
}
+/** Mask off a portion of an IPv4 address
+ *
+ * @param ipaddr to mask.
+ * @param prefix Number of contiguous bits to mask.
+ * @return an ipv6 address with the host portion zeroed out.
+ */
+struct in_addr fr_inaddr_mask(struct in_addr const *ipaddr, uint8_t prefix)
+{
+ uint32_t ret;
+
+ if (prefix > 32) {
+ prefix = 32;
+ }
+
+ /* Short circuit */
+ if (prefix == 32) {
+ return *ipaddr;
+ }
+
+ ret = htonl(~((0x00000001UL << (32 - prefix)) - 1)) & ipaddr->s_addr;
+ return (*(struct in_addr *)&ret);
+}
+
+/** Mask off a portion of an IPv6 address
+ *
+ * @param ipaddr to mask.
+ * @param prefix Number of contiguous bits to mask.
+ * @return an ipv6 address with the host portion zeroed out.
+ */
+struct in6_addr fr_in6addr_mask(struct in6_addr const *ipaddr, uint8_t prefix)
+{
+ uint64_t const *p = (uint64_t const *) ipaddr;
+ uint64_t ret[2], *o = ret;
+
+ if (prefix > 128) {
+ prefix = 128;
+ }
+
+ /* Short circuit */
+ if (prefix == 128) {
+ return *ipaddr;
+ }
+
+ if (prefix >= 64) {
+ prefix -= 64;
+ *o++ = 0xffffffffffffffffULL & *p++;
+ } else {
+ ret[1] = 0;
+ }
+
+ *o = htonll(~((0x0000000000000001ULL << (64 - prefix)) - 1)) & *p;
+
+ return *(struct in6_addr *) &ret;
+}
+
+/** Zeroes out the host portion of an fr_ipaddr_t
+ *
+ * @param[in,out] addr to mask
+ * @param[in] prefix Length of the network portion.
+ */
+void fr_ipaddr_mask(fr_ipaddr_t *addr, uint8_t prefix)
+{
+
+ switch (addr->af) {
+ case AF_INET:
+ addr->ipaddr.ip4addr = fr_inaddr_mask(&addr->ipaddr.ip4addr, prefix);
+ break;
+
+ case AF_INET6:
+ addr->ipaddr.ip6addr = fr_in6addr_mask(&addr->ipaddr.ip6addr, prefix);
+ break;
+
+ default:
+ return;
+ }
+ addr->prefix = prefix;
+}
static char const *hextab = "0123456789abcdef";
return strtoul(value, end, 10);
}
-/** Check whether the rest of the string is whitespace
+/** Check whether the string is all whitespace
*
* @return true if the entirety of the string is whitespace, else false.
*/
-bool fr_whitespace_check(char const *value)
+bool is_whitespace(char const *value)
{
- while (*value) {
- if (!isspace((int) *value)) return false;
+ do {
+ if (!isspace(*value)) return false;
+ } while (*++value);
- value++;
- }
+ return true;
+}
+
+/** Check whether the string is all numbers
+ *
+ * @return true if the entirety of the string is are numebrs, else false.
+ */
+bool is_integer(char const *value)
+{
+ do {
+ if (!isdigit(*value)) return false;
+ } while (*++value);
+
+ return true;
+}
+
+/** Check whether the string is allzeros
+ *
+ * @return true if the entirety of the string is are numebrs, else false.
+ */
+bool is_zero(char const *value)
+{
+ do {
+ if (*value != '0') return false;
+ } while (*++value);
return true;
}
return -1;
}
-int fr_ipaddr2sockaddr(fr_ipaddr_t const *ipaddr, int port,
+int fr_ipaddr2sockaddr(fr_ipaddr_t const *ipaddr, uint16_t port,
struct sockaddr_storage *sa, socklen_t *salen)
{
if (ipaddr->af == AF_INET) {
int fr_sockaddr2ipaddr(struct sockaddr_storage const *sa, socklen_t salen,
- fr_ipaddr_t *ipaddr, int *port)
+ fr_ipaddr_t *ipaddr, uint16_t *port)
{
if (sa->ss_family == AF_INET) {
struct sockaddr_in s4;
memcpy(&s4, sa, sizeof(s4));
ipaddr->af = AF_INET;
+ ipaddr->prefix = 32;
ipaddr->ipaddr.ip4addr = s4.sin_addr;
if (port) *port = ntohs(s4.sin_port);
memcpy(&s6, sa, sizeof(s6));
ipaddr->af = AF_INET6;
+ ipaddr->prefix = 128;
ipaddr->ipaddr.ip6addr = s6.sin6_addr;
if (port) *port = ntohs(s6.sin6_port);
ipaddr->scope = s6.sin6_scope_id;
return out - start;
}
+/** Write 128bit unsigned integer to buffer
+ *
+ * @author Alexey Frunze
+ *
+ * @param out where to write result to.
+ * @param outlen size of out.
+ * @param num 128 bit integer.
+ */
+size_t fr_prints_uint128(char *out, size_t outlen, uint128_t const num)
+{
+ char buff[128 / 3 + 1 + 1];
+ uint64_t n[2];
+ char *p = buff;
+ int i;
+
+ memset(buff, '0', sizeof(buff) - 1);
+ buff[sizeof(buff) - 1] = '\0';
+
+ memcpy(n, &num, sizeof(n));
+
+ for (i = 0; i < 128; i++) {
+ ssize_t j;
+ int carry;
+
+ carry = (n[1] >= 0x8000000000000000);
+
+ // Shift n[] left, doubling it
+ n[1] = ((n[1] << 1) & 0xffffffffffffffff) + (n[0] >= 0x8000000000000000);
+ n[0] = ((n[0] << 1) & 0xffffffffffffffff);
+
+ // Add s[] to itself in decimal, doubling it
+ for (j = sizeof(buff) - 2; j >= 0; j--) {
+ buff[j] += buff[j] - '0' + carry;
+ carry = (buff[j] > '9');
+ if (carry) {
+ buff[j] -= 10;
+ }
+ }
+ }
+
+ while ((*p == '0') && (p < &buff[sizeof(buff) - 2])) {
+ p++;
+ }
+
+ return strlcpy(out, p, outlen);
+}
+
/** Calculate powers
*
* @author Orson Peters
char buf[64];
char *p;
char *f[4];
- char *tail = '\0';
+ char *tail = NULL;
/*
* Test for unix timestamp date
return 0;
}
+/** Compares two pointers
+ *
+ * @param a first pointer to compare.
+ * @param b second pointer to compare.
+ * @return -1 if a < b, +1 if b > a, or 0 if both equal.
+ */
+int8_t fr_pointer_cmp(void const *a, void const *b)
+{
+ if (a < b) return -1;
+ if (a == b) return 0;
+
+ return 1;
+}
+
+static int _quick_partition(void const *to_sort[], int min, int max, fr_cmp_t cmp) {
+ void const *pivot = to_sort[min];
+ int i = min;
+ int j = max + 1;
+ void const *tmp;
+
+ for (;;) {
+ do ++i; while((cmp(to_sort[i], pivot) <= 0) && i <= max);
+ do --j; while(cmp(to_sort[j], pivot) > 0);
+
+ if (i >= j) break;
+
+ tmp = to_sort[i];
+ to_sort[i] = to_sort[j];
+ to_sort[j] = tmp;
+ }
+
+ tmp = to_sort[min];
+ to_sort[min] = to_sort[j];
+ to_sort[j] = tmp;
+
+ return j;
+}
+
+/** Quick sort an array of pointers using a comparator
+ *
+ * @param to_sort array of pointers to sort.
+ * @param min_idx the lowest index (usually 0).
+ * @param max_idx the highest index (usually length of array - 1).
+ * @param cmp the comparison function to use to sort the array elements.
+ */
+void fr_quick_sort(void const *to_sort[], int min_idx, int max_idx, fr_cmp_t cmp)
+{
+ int part;
+
+ if (min_idx >= max_idx) return;
+
+ part = _quick_partition(to_sort, min_idx, max_idx, cmp);
+ fr_quick_sort(to_sort, min_idx, part - 1, cmp);
+ fr_quick_sort(to_sort, part + 1, max_idx, cmp);
+}
+
#ifdef TALLOC_DEBUG
void fr_talloc_verify_cb(UNUSED const void *ptr, UNUSED int depth,
UNUSED int max_depth, UNUSED int is_ref,
tv->tv_sec = sec - NTP_EPOCH_OFFSET;
tv->tv_usec = usec / 4295; /* close enough */
}
+
+#if !defined(HAVE_128BIT_INTEGERS) && defined(LITTLE_ENDIAN)
+/** Swap byte order of 128 bit integer
+ *
+ * @param num 128bit integer to swap.
+ * @return 128bit integer reversed.
+ */
+uint128_t ntohlll(uint128_t const num)
+{
+ uint64_t const *p = (uint64_t const *) #
+ uint64_t ret[2];
+
+ /* swapsies */
+ ret[1] = ntohll(p[0]);
+ ret[0] = ntohll(p[1]);
+
+ return *(uint128_t *)ret;
+}
+#endif
+
+/** Call talloc strdup, setting the type on the new chunk correctly
+ *
+ * For some bizarre reason the talloc string functions don't set the
+ * memory chunk type to char, which causes all kinds of issues with
+ * verifying VALUE_PAIRs.
+ *
+ * @param[in] t The talloc context to hang the result off.
+ * @param[in] p The string you want to duplicate.
+ * @return The duplicated string, NULL on error.
+ */
+char *talloc_typed_strdup(void const *t, char const *p)
+{
+ char *n;
+
+ n = talloc_strdup(t, p);
+ if (!n) return NULL;
+ talloc_set_type(n, char);
+
+ return n;
+}
+
+/** Call talloc vasprintf, setting the type on the new chunk correctly
+ *
+ * For some bizarre reason the talloc string functions don't set the
+ * memory chunk type to char, which causes all kinds of issues with
+ * verifying VALUE_PAIRs.
+ *
+ * @param[in] t The talloc context to hang the result off.
+ * @param[in] fmt The format string.
+ * @return The formatted string, NULL on error.
+ */
+char *talloc_typed_asprintf(void const *t, char const *fmt, ...)
+{
+ char *n;
+ va_list ap;
+
+ va_start(ap, fmt);
+ n = talloc_vasprintf(t, fmt, ap);
+ va_end(ap);
+ if (!n) return NULL;
+ talloc_set_type(n, char);
+
+ return n;
+}
request->dst_ipaddr = reply->src_ipaddr;
}
-
-int fr_nonblock(UNUSED int fd)
-{
- int flags = 0;
-
#ifdef O_NONBLOCK
+int fr_nonblock(int fd)
+{
+ int flags;
flags = fcntl(fd, F_GETFL, NULL);
- if (flags >= 0) {
- flags |= O_NONBLOCK;
- return fcntl(fd, F_SETFL, flags);
+ if (flags < 0) {
+ fr_strerror_printf("Failure getting socket flags: %s", fr_syserror(errno));
+ return -1;
}
-#endif
+
+ flags |= O_NONBLOCK;
+ if (fcntl(fd, F_SETFL, flags) < 0) {
+ fr_strerror_printf("Failure setting socket flags: %s", fr_syserror(errno));
+ return -1;
+ }
+
return flags;
}
+#else
+int fr_nonblock(UNUSED int fd)
+{
+ return 0;
+}
+#endif
/*
* Open a socket on the given IP and port.
*/
-int fr_socket(fr_ipaddr_t *ipaddr, int port)
+int fr_socket(fr_ipaddr_t *ipaddr, uint16_t port)
{
int sockfd;
struct sockaddr_storage salocal;
socklen_t salen;
- if ((port < 0) || (port > 65535)) {
- fr_strerror_printf("Port %d is out of allowed bounds", port);
- return -1;
- }
-
sockfd = socket(ipaddr->af, SOCK_DGRAM, 0);
if (sockfd < 0) {
- fr_strerror_printf("cannot open socket: %s", strerror(errno));
+ fr_strerror_printf("cannot open socket: %s", fr_syserror(errno));
return sockfd;
}
*/
if (udpfromto_init(sockfd) != 0) {
close(sockfd);
- fr_strerror_printf("cannot initialize udpfromto: %s", strerror(errno));
+ fr_strerror_printf("cannot initialize udpfromto: %s", fr_syserror(errno));
return -1;
}
#endif
close(sockfd);
fr_strerror_printf("Failed setting sockopt "
"IPPROTO_IPV6 - IPV6_V6ONLY"
- ": %s", strerror(errno));
+ ": %s", fr_syserror(errno));
return -1;
}
}
close(sockfd);
fr_strerror_printf("Failed setting sockopt "
"IPPROTO_IP - IP_MTU_DISCOVER: %s",
- strerror(errno));
+ fr_syserror(errno));
return -1;
}
#endif
close(sockfd);
fr_strerror_printf("Failed setting sockopt "
"IPPROTO_IP - IP_DONTFRAG: %s",
- strerror(errno));
+ fr_syserror(errno));
return -1;
}
#endif
if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
close(sockfd);
- fr_strerror_printf("cannot bind socket: %s", strerror(errno));
+ fr_strerror_printf("cannot bind socket: %s", fr_syserror(errno));
return -1;
}
int sockfd;
void *ctx;
- int num_outgoing;
+ uint32_t num_outgoing;
int src_any;
fr_ipaddr_t src_ipaddr;
- int src_port;
+ uint16_t src_port;
int dst_any;
fr_ipaddr_t dst_ipaddr;
- int dst_port;
+ uint16_t dst_port;
- int dont_use;
+ bool dont_use;
#ifdef WITH_TCP
int proto;
rbtree_t *tree;
int alloc_id;
- int num_outgoing;
+ uint32_t num_outgoing;
int last_recv;
int num_sockets;
return false;
}
- ps->dont_use = 1;
+ ps->dont_use = true;
return true;
}
ps = fr_socket_find(pl, sockfd);
if (!ps) return false;
- ps->dont_use = 0;
+ ps->dont_use = false;
return true;
}
ps = fr_socket_find(pl, sockfd);
if (!ps) return false;
- if (ps->num_outgoing != 0) return false;
+ if (ps->num_outgoing != 0) {
+ fr_strerror_printf("socket is still in use");
+ return false;
+ }
ps->sockfd = -1;
pl->num_sockets--;
bool fr_packet_list_socket_add(fr_packet_list_t *pl, int sockfd, int proto,
- fr_ipaddr_t *dst_ipaddr, int dst_port,
+ fr_ipaddr_t *dst_ipaddr, uint16_t dst_port,
void *ctx)
{
int i, start;
memset(&src, 0, sizeof_src);
if (getsockname(sockfd, (struct sockaddr *) &src,
&sizeof_src) < 0) {
- fr_strerror_printf("%s", strerror(errno));
+ fr_strerror_printf("%s", fr_syserror(errno));
return false;
}
return true;
}
-int fr_packet_list_num_elements(fr_packet_list_t *pl)
+uint32_t fr_packet_list_num_elements(fr_packet_list_t *pl)
{
if (!pl) return 0;
if (fr_packet_list_insert(pl, request_p)) {
if (pctx) *pctx = ps->ctx;
ps->num_outgoing++;
- pl->num_outgoing++;
+ pl->num_outgoing++;
return true;
}
pl->num_outgoing--;
request->id = -1;
+ request->src_ipaddr.af = AF_UNSPEC; /* id_alloc checks this */
+ request->src_port = 0;
return true;
}
/*
- * We always walk DeleteOrder, which is like InOrder, except that
+ * We always walk RBTREE_DELETE_ORDER, which is like RBTREE_IN_ORDER, except that
* <0 means error, stop
* 0 means OK, continue
* 1 means delete current node and stop
* 2 means delete current node and continue
*/
-int fr_packet_list_walk(fr_packet_list_t *pl, void *ctx,
- fr_hash_table_walk_t callback)
+int fr_packet_list_walk(fr_packet_list_t *pl, void *ctx, rb_walker_t callback)
{
if (!pl || !callback) return 0;
- return rbtree_walk(pl->tree, DeleteOrder, callback, ctx);
+ return rbtree_walk(pl->tree, RBTREE_DELETE_ORDER, callback, ctx);
}
int fr_packet_list_fd_set(fr_packet_list_t *pl, fd_set *set)
return NULL;
}
-int fr_packet_list_num_incoming(fr_packet_list_t *pl)
+uint32_t fr_packet_list_num_incoming(fr_packet_list_t *pl)
{
- int num_elements;
+ uint32_t num_elements;
if (!pl) return 0;
return num_elements - pl->num_outgoing;
}
-int fr_packet_list_num_outgoing(fr_packet_list_t *pl)
+uint32_t fr_packet_list_num_outgoing(fr_packet_list_t *pl)
{
if (!pl) return 0;
--- /dev/null
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 if the
+ * License as published by the Free Software Foundation.
+ *
+ * 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
+ */
+
+/**
+ * $Id$
+ * @file pcap.c
+ * @brief Wrappers around libpcap functions
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+#ifdef HAVE_LIBPCAP
+
+#include <sys/ioctl.h>
+#include <pcap/pcap.h>
+#include <freeradius-devel/pcap.h>
+
+const FR_NAME_NUMBER pcap_types[] = {
+ { "interface", PCAP_INTERFACE_IN },
+ { "file", PCAP_FILE_IN },
+ { "stdio", PCAP_STDIO_IN },
+ { "interface", PCAP_INTERFACE_OUT },
+ { "file", PCAP_FILE_OUT },
+ { "stdio", PCAP_STDIO_OUT },
+
+ { NULL, 0}
+};
+
+/** Talloc destructor to free pcap resources associated with a handle.
+ *
+ * @param pcap to free.
+ * @return 0
+ */
+static int _free_pcap(fr_pcap_t *pcap) {
+ switch (pcap->type) {
+ case PCAP_INTERFACE_IN:
+ case PCAP_INTERFACE_OUT:
+ case PCAP_FILE_IN:
+ case PCAP_STDIO_IN:
+ if (pcap->handle) {
+ pcap_close(pcap->handle);
+
+ if (pcap->fd > 0) {
+ close(pcap->fd);
+ }
+ }
+
+ break;
+
+ case PCAP_FILE_OUT:
+ case PCAP_STDIO_OUT:
+ if (pcap->dumper) {
+ pcap_dump_flush(pcap->dumper);
+ pcap_dump_close(pcap->dumper);
+ }
+
+ break;
+ case PCAP_INVALID:
+ break;
+ }
+
+ return 0;
+}
+
+/** Initialise a pcap handle abstraction
+ *
+ * @param ctx talloc TALLOC_CTX to allocate handle in.
+ * @param name of interface or file to open.
+ * @param type of handle to initialise.
+ * @return new handle or NULL on error.
+ */
+fr_pcap_t *fr_pcap_init(TALLOC_CTX *ctx, char const *name, fr_pcap_type_t type)
+{
+ fr_pcap_t *this = talloc_zero(ctx, fr_pcap_t);
+ if (!this) {
+ return NULL;
+ }
+
+ talloc_set_destructor(this, _free_pcap);
+ this->name = talloc_typed_strdup(this, name);
+ this->type = type;
+ this->link_type = -1;
+
+ return this;
+}
+
+/** Open a PCAP handle abstraction
+ *
+ * This opens interfaces for capture or injection, or files/streams for reading/writing.
+ * @param pcap created with fr_pcap_init.
+ * @return 0 on success, -1 on error.
+ */
+int fr_pcap_open(fr_pcap_t *pcap)
+{
+ switch (pcap->type) {
+ case PCAP_INTERFACE_OUT:
+ case PCAP_INTERFACE_IN:
+ {
+#if defined(HAVE_PCAP_CREATE) && defined(HAVE_PCAP_ACTIVATE)
+ pcap->handle = pcap_create(pcap->name, pcap->errbuf);
+ if (!pcap->handle) {
+ fr_strerror_printf("%s", pcap->errbuf);
+ return -1;
+ }
+ if (pcap_set_snaplen(pcap->handle, SNAPLEN) != 0) {
+ create_error:
+ fr_strerror_printf("%s", pcap_geterr(pcap->handle));
+ pcap_close(pcap->handle);
+ pcap->handle = NULL;
+ return -1;
+ }
+ if (pcap_set_timeout(pcap->handle, PCAP_NONBLOCK_TIMEOUT) != 0) {
+ goto create_error;
+ }
+ if (pcap_set_promisc(pcap->handle, pcap->promiscuous) != 0) {
+ goto create_error;
+ }
+
+ if (pcap_set_buffer_size(pcap->handle, SNAPLEN *
+ (pcap->buffer_pkts ? pcap->buffer_pkts : PCAP_BUFFER_DEFAULT)) != 0) {
+ goto create_error;
+ }
+ if (pcap_activate(pcap->handle) != 0) {
+ goto create_error;
+ }
+#else
+ /*
+ * Alternative functions for libpcap < 1.0
+ */
+ pcap->handle = pcap_open_live(pcap->name, SNAPLEN, pcap->promiscuous, PCAP_NONBLOCK_TIMEOUT,
+ pcap->errbuf);
+ if (!pcap->handle) {
+ fr_strerror_printf("%s", pcap->errbuf);
+ return -1;
+ }
+#endif
+ /*
+ * Despite accepting an errbuff, pcap_setnonblock doesn't seem to write
+ * error message there in newer versions.
+ */
+ if (pcap_setnonblock(pcap->handle, true, pcap->errbuf) != 0) {
+ fr_strerror_printf("%s", *pcap->errbuf != '\0' ?
+ pcap->errbuf : pcap_geterr(pcap->handle));
+ pcap_close(pcap->handle);
+ pcap->handle = NULL;
+ return -1;
+ }
+
+ pcap->fd = pcap_get_selectable_fd(pcap->handle);
+ pcap->link_type = pcap_datalink(pcap->handle);
+#ifndef __linux__
+ {
+ int value = 1;
+ if (ioctl(pcap->fd, BIOCIMMEDIATE, &value) < 0) {
+ fr_strerror_printf("Failed setting BIOCIMMEDIATE: %s", fr_syserror(errno));
+ }
+ }
+#endif
+ }
+ break;
+
+ case PCAP_FILE_IN:
+ pcap->handle = pcap_open_offline(pcap->name, pcap->errbuf);
+ if (!pcap->handle) {
+ fr_strerror_printf("%s", pcap->errbuf);
+
+ return -1;
+ }
+ pcap->fd = pcap_get_selectable_fd(pcap->handle);
+ pcap->link_type = pcap_datalink(pcap->handle);
+ break;
+
+ case PCAP_FILE_OUT:
+ if (pcap->link_type < 0) {
+ pcap->link_type = DLT_EN10MB;
+ }
+ pcap->handle = pcap_open_dead(pcap->link_type, SNAPLEN);
+ if (!pcap->handle) {
+ fr_strerror_printf("Unknown error occurred opening dead PCAP handle");
+
+ return -1;
+ }
+ pcap->dumper = pcap_dump_open(pcap->handle, pcap->name);
+ if (!pcap->dumper) {
+ fr_strerror_printf("%s", pcap_geterr(pcap->handle));
+
+ return -1;
+ }
+ break;
+
+#ifdef HAVE_PCAP_FOPEN_OFFLINE
+ case PCAP_STDIO_IN:
+ pcap->handle = pcap_fopen_offline(stdin, pcap->errbuf);
+ if (!pcap->handle) {
+ fr_strerror_printf("%s", pcap->errbuf);
+
+ return -1;
+ }
+ pcap->fd = pcap_get_selectable_fd(pcap->handle);
+ pcap->link_type = pcap_datalink(pcap->handle);
+ break;
+#else
+ case PCAP_STDIO_IN:
+ fr_strerror_printf("This version of libpcap does not support reading pcap data from streams");
+
+ return -1;
+#endif
+#ifdef HAVE_PCAP_DUMP_FOPEN
+ case PCAP_STDIO_OUT:
+ pcap->handle = pcap_open_dead(DLT_EN10MB, SNAPLEN);
+ pcap->dumper = pcap_dump_fopen(pcap->handle, stdout);
+ if (!pcap->dumper) {
+ fr_strerror_printf("%s", pcap_geterr(pcap->handle));
+
+ return -1;
+ }
+ break;
+#else
+ case PCAP_STDIO_OUT:
+ fr_strerror_printf("This version of libpcap does not support writing pcap data to streams");
+
+ return -1;
+#endif
+ case PCAP_INVALID:
+ default:
+ fr_assert(0);
+ fr_strerror_printf("Bad handle type (%i)", pcap->type);
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Apply capture filter to an interface
+ *
+ * @param pcap handle to apply filter to.
+ * @param expression PCAP expression to use as a filter.
+ * @return 0 on success, 1 can't apply to interface, -1 on error.
+ */
+int fr_pcap_apply_filter(fr_pcap_t *pcap, char const *expression)
+{
+ bpf_u_int32 mask = 0; /* Our netmask */
+ bpf_u_int32 net = 0; /* Our IP */
+ struct bpf_program fp;
+
+ /*
+ * nflog devices are in the set of devices selected by default.
+ * Unfortunately there's a bug in all released version of libpcap (as of 2/1/2014)
+ * which triggers an abort if pcap_setfilter is called on an nflog interface.
+ *
+ * See here:
+ * https://github.com/the-tcpdump-group/libpcap/commit/676cf8a61ed240d0a86d471ef419f45ba35dba80
+ */
+#ifdef DLT_NFLOG
+ if (pcap->link_type == DLT_NFLOG) {
+ fr_strerror_printf("NFLOG link-layer type filtering not implemented");
+
+ return 1;
+ }
+#endif
+
+ if (pcap->type == PCAP_INTERFACE_IN) {
+ if (pcap_lookupnet(pcap->name, &net, &mask, pcap->errbuf) < 0) {
+ fr_strerror_printf("Failed getting IP for interface \"%s\", using defaults: %s",
+ pcap->name, pcap->errbuf);
+ }
+ }
+
+ if (pcap_compile(pcap->handle, &fp, expression, 0, net) < 0) {
+ fr_strerror_printf("%s", pcap_geterr(pcap->handle));
+
+ return -1;
+ }
+
+ if (pcap_setfilter(pcap->handle, &fp) < 0) {
+ fr_strerror_printf("%s", pcap_geterr(pcap->handle));
+
+ return -1;
+ }
+
+ return 0;
+}
+
+char *fr_pcap_device_names(TALLOC_CTX *ctx, fr_pcap_t *pcap, char c)
+{
+ fr_pcap_t *pcap_p;
+ char *buff, *p;
+ size_t len = 0, left = 0, wrote;
+
+ if (!pcap) {
+ goto null;
+ }
+
+ for (pcap_p = pcap;
+ pcap_p;
+ pcap_p = pcap_p->next) {
+ len += talloc_array_length(pcap_p->name); // Talloc array length includes the \0
+ }
+
+ if (!len) {
+ null:
+ return talloc_zero_array(ctx, char, 1);
+ }
+
+ left = len + 1;
+ buff = p = talloc_zero_array(ctx, char, left);
+ for (pcap_p = pcap;
+ pcap_p;
+ pcap_p = pcap_p->next) {
+ wrote = snprintf(p, left, "%s%c", pcap_p->name, c);
+ left -= wrote;
+ p += wrote;
+ }
+ buff[len - 1] = '\0';
+
+ return buff;
+}
+
+/** Returns the length of the link layer header
+ *
+ * Libpcap does not include a decoding function to skip the L2 header, but it does
+ * at least inform us of the type.
+ *
+ * Unfortunately some headers are of variable length (like ethernet), so additional
+ * decoding logic is required.
+ *
+ * @note No header data is returned, this is only meant to be used to determine how
+ * data to consume before attempting to parse the IP header.
+ *
+ * @param data start of PCAP data.
+ * @param len caplen.
+ * @param link_type value returned from pcap_linktype.
+ * @return the length of the header, or -1 on error.
+ */
+ssize_t fr_pcap_link_layer_offset(uint8_t const *data, size_t len, int link_type)
+{
+ uint8_t const *p = data;
+
+ switch (link_type) {
+ case DLT_RAW:
+ break;
+
+ case DLT_NULL:
+ case DLT_LOOP:
+ p += 4;
+ if (((size_t)(p - data)) > len) {
+ goto ood;
+ }
+ break;
+
+ case DLT_EN10MB:
+ {
+ uint16_t ether_type; /* Ethernet type */
+ int i;
+
+ p += 12; /* SRC/DST Mac-Addresses */
+ if (((size_t)(p - data)) > len) {
+ goto ood;
+ }
+
+ for (i = 0; i < 3; i++) {
+ ether_type = ntohs(*((uint16_t const *) p));
+ switch (ether_type) {
+ /*
+ * There are a number of devices out there which
+ * double tag with 0x8100 *sigh*
+ */
+ case 0x8100: /* CVLAN */
+ case 0x9100: /* SVLAN */
+ case 0x9200: /* SVLAN */
+ case 0x9300: /* SVLAN */
+ p += 4;
+ if (((size_t)(p - data)) > len) {
+ goto ood;
+ }
+ break;
+
+ default:
+ p += 2;
+ if (((size_t)(p - data)) > len) {
+ goto ood;
+ }
+ goto done;
+ }
+ }
+ fr_strerror_printf("Exceeded maximum level of VLAN tag nesting (2)");
+ return -1;
+ }
+
+ case DLT_LINUX_SLL:
+ p += 16;
+ if (((size_t)(p - data)) > len) {
+ goto ood;
+ }
+ break;
+
+ case DLT_PFLOG:
+ p += 28;
+ if (((size_t)(p - data)) > len) {
+ goto ood;
+ }
+ break;
+
+ default:
+ fr_strerror_printf("Unsupported link layer type %i", link_type);
+ }
+
+ done:
+ return p - data;
+
+ ood:
+ fr_strerror_printf("Out of data, needed %zu bytes, have %zu bytes", (size_t)(p - data), len);
+
+ return -1;
+}
+
+/** Calculate UDP checksum
+ *
+ * Zero out UDP checksum in UDP header before calling fr_udp_checksum to get 'expected' checksum.
+ *
+ * @param data Pointer to the start of the UDP header
+ * @param len value of udp length field in host byte order. Must be validated to make
+ * sure it won't overrun data buffer.
+ * @param checksum current checksum, leave as 0 to just enable validation.
+ * @param src_addr in network byte order.
+ * @param dst_addr in network byte order.
+ * @return 0 if the checksum is correct, else another number.
+ */
+uint16_t fr_udp_checksum(uint8_t const *data, uint16_t len, uint16_t checksum,
+ struct in_addr const src_addr, struct in_addr const dst_addr)
+{
+ uint64_t sum = 0; /* using 64bits avoids overflow check */
+ uint16_t const *p = (uint16_t const *)data;
+
+ uint16_t const *ip_src = (void const *) &src_addr.s_addr;
+ uint16_t const *ip_dst = (void const *) &dst_addr.s_addr;
+ uint16_t i;
+
+ sum += *(ip_src++);
+ sum += *ip_src;
+ sum += *(ip_dst++);
+ sum += *ip_dst;
+
+ sum += htons(IPPROTO_UDP);
+ sum += htons(len);
+
+ for (i = len; i > 1; i -= 2) {
+ sum += *p++;
+ }
+
+ if (i) {
+ sum += (0xff & *(uint8_t const *)p) << 8;
+ }
+
+ sum -= checksum;
+
+ while (sum >> 16) {
+ sum = (sum & 0xffff) + (sum >> 16);
+ }
+
+ return ((uint16_t) ~sum);
+}
+#endif
return 0;
}
-/*
- * Convert a string to something printable. The output string
- * has to be larger than the input string by at least 5 bytes.
- * If not, the output is silently truncated...
+/** Escape any non printable or non-UTF8 characters in the input string
+ *
+ * @param[in] in string to escape.
+ * @param[in] inlen length of string to escape (lets us deal with embedded NULLs)
+ * @param[out] out where to write the escaped string.
+ * @param[out] outlen the length of the buffer pointed to by out.
+ * @return the number of bytes written to the out buffer, or a number > outlen if truncation has occurred.
*/
size_t fr_print_string(char const *in, size_t inlen, char *out, size_t outlen)
{
- char const *start = out;
- uint8_t const *str = (uint8_t const *) in;
+ uint8_t const *p = (uint8_t const *) in;
int sp = 0;
int utf8 = 0;
+ size_t freespace = outlen;
- if (!in) {
- if (outlen) {
- *out = '\0';
- }
+ /* Can't '\0' terminate */
+ if (freespace == 0) {
+ return inlen;
+ }
+ /* No input, so no output... */
+ if (!in) {
+ no_input:
+ *out = '\0';
return 0;
}
- if (inlen == 0) {
- inlen = strlen(in);
+ /* Figure out the length of the input string */
+ if (inlen == 0) inlen = strlen(in);
+
+ /* Not enough space to hold one char */
+ if (freespace < 2) {
+ /* And there's input data... */
+ if (inlen > 0) {
+ *out = '\0';
+ return inlen;
+ }
+
+ goto no_input;
}
- /*
- *
- */
- while ((inlen > 0) && (outlen > 4)) {
+ while (inlen > 0) {
/*
* Hack: never print trailing zero.
- * Some clients send strings with an off-by-one
+ * Some clients send pings with an off-by-one
* length (confused with strings in C).
*/
- if ((inlen == 1) && (*str == 0)) break;
-
- switch (*str) {
- case '\\':
- sp = '\\';
- break;
- case '\r':
- sp = 'r';
- break;
- case '\n':
- sp = 'n';
- break;
- case '\t':
- sp = 't';
- break;
- case '"':
- sp = '"';
- break;
- default:
- sp = 0;
- break;
+ if ((inlen == 1) && (*p == '\0')) {
+ inlen--;
+ break;
+ }
+ switch (*p) {
+ case '\\':
+ sp = '\\';
+ break;
+ case '\r':
+ sp = 'r';
+ break;
+ case '\n':
+ sp = 'n';
+ break;
+ case '\t':
+ sp = 't';
+ break;
+ case '"':
+ sp = '"';
+ break;
+ default:
+ sp = '\0';
+ break;
}
if (sp) {
+ if (freespace < 3) break; /* \ + <c> + \0 */
*out++ = '\\';
*out++ = sp;
- outlen -= 2;
- str++;
+ freespace -= 2;
+ p++;
inlen--;
continue;
}
- utf8 = fr_utf8_char(str);
- if (!utf8) {
- snprintf(out, outlen, "\\%03o", *str);
- out += 4;
- outlen -= 4;
- str++;
+ utf8 = fr_utf8_char(p);
+ if (utf8 == 0) {
+ if (freespace < 5) break; /* \ + <o><o><o> + \0 */
+ snprintf(out, freespace, "\\%03o", *p);
+ out += 4;
+ freespace -= 4;
+ p++;
inlen--;
continue;
}
do {
- *out++ = *str++;
- outlen--;
+ if (freespace < 2) goto finish; /* <c> + \0 */
+ *out++ = *p++;
+ freespace--;
inlen--;
} while (--utf8 > 0);
}
+
+finish:
*out = '\0';
- return out - start;
+ /* Indicate truncation occurred */
+ if (inlen > 0) return outlen + inlen;
+
+ return outlen - freespace;
+}
+
+/** Find the length of the buffer required to fully escape a string with fr_print_string
+ *
+ * Were assuming here that's it's cheaper to figure out the length and do one
+ * alloc than repeatedly expand the buffer when we find extra chars which need
+ * to be added.
+ *
+ * @param in string to calculate the escaped length for.
+ * @param inlen length of the input string, if 0 strlen will be used to check the length.
+ * @return the size of buffer required to hold the escaped string excluding the NULL byte.
+ */
+size_t fr_print_string_len(char const *in, size_t inlen)
+{
+ uint8_t const *p = (uint8_t const *) in;
+ size_t outlen = 0;
+ int utf8 = 0;
+
+ if (!in) {
+ return 0;
+ }
+
+ if (inlen == 0) {
+ inlen = strlen(in);
+ }
+
+ while (inlen > 0) {
+ /*
+ * Hack: never print trailing zero. Some clients send pings
+ * with an off-by-one length (confused with strings in C).
+ */
+ if ((inlen == 1) && (*p == '\0')) {
+ inlen--;
+ break;
+ }
+
+ switch (*p) {
+ case '\\':
+ case '\r':
+ case '\n':
+ case '\t':
+ case '"':
+ outlen += 2;
+ p++;
+ inlen--;
+ continue;
+
+ default:
+ break;
+ }
+
+ utf8 = fr_utf8_char(p);
+ if (utf8 == 0) {
+ outlen += 4;
+ p++;
+ inlen--;
+ continue;
+ }
+
+ do {
+ outlen++;
+ p++;
+ inlen--;
+ } while (--utf8 > 0);
+ }
+
+ return outlen;
}
* @param[in] vp to print.
* @param[in] quote Char to add before and after printed value, if 0 no char will be added, if < 0 raw string will be
* added.
- * @return length of data written to out or 0 on error.
+ * @return the length of data written to out, or a value >= outlen on truncation.
*/
size_t vp_prints_value(char *out, size_t outlen, VALUE_PAIR const *vp, int8_t quote)
{
DICT_VALUE *v;
- char buf[1024];
+ char buf[1024]; /* Interim buffer to use with poorly behaved printing functions */
char const *a = NULL;
time_t t;
struct tm s_tm;
- char *start = out;
- size_t len, freespace = outlen;
-
- *out = '\0';
+ size_t len = 0, freespace = outlen;
if (!vp) return 0;
+ VERIFY_VP(vp);
+
+ if (outlen == 0) return vp->length;
+
+ *out = '\0';
+
switch (vp->da->type) {
case PW_TYPE_STRING:
/* need to copy the escaped value, but quoted */
if (quote > 0) {
if (freespace < 3) {
- return 0;
+ return vp->length + 2;
}
*out++ = (char) quote;
if (len >= (freespace - 1)) {
out[outlen - 2] = (char) quote;
out[outlen - 1] = '\0';
- return outlen - 1;
+ return len + 2;
}
out += len;
freespace -= len;
freespace--;
*out = '\0';
- return out - start;
+ return len + 2;
}
/* xlat.c - need to copy raw value verbatim */
- if (quote < 0) {
- strlcpy(out, vp->vp_strvalue, outlen);
- return strlen(out);
+ else if (quote < 0) {
+ if (outlen > vp->length) {
+ memcpy(out, vp->vp_strvalue, vp->length + 1);
+ return vp->length;
+ }
+
+ memcpy(out, vp->vp_strvalue, outlen);
+ out[outlen - 1] = '\0';
+ return vp->length; /* not a typo */
}
- return fr_print_string(vp->vp_strvalue, vp->length, out, sizeof(out));
+ return fr_print_string(vp->vp_strvalue, vp->length, out, outlen);
case PW_TYPE_INTEGER:
if (vp->da->flags.has_tag) {
/* Attribute value has a tag, need to ignore it */
- if ((v = dict_valbyattr(vp->da->attr, vp->da->vendor, (vp->vp_integer & 0xffffff)))
- != NULL)
+ if ((v = dict_valbyattr(vp->da->attr, vp->da->vendor, (vp->vp_integer & 0xffffff))) != NULL) {
a = v->name;
- else {
- snprintf(buf, sizeof(buf), "%u", (vp->vp_integer & 0xffffff));
+ len = strlen(a);
+ } else {
+ /* should never be truncated */
+ len = snprintf(buf, sizeof(buf), "%u", (vp->vp_integer & 0xffffff));
a = buf;
}
} else {
case PW_TYPE_BYTE:
case PW_TYPE_SHORT:
/* Normal, non-tagged attribute */
- if ((v = dict_valbyattr(vp->da->attr, vp->da->vendor, vp->vp_integer))
- != NULL)
+ if ((v = dict_valbyattr(vp->da->attr, vp->da->vendor, vp->vp_integer)) != NULL) {
a = v->name;
- else {
- snprintf(buf, sizeof(buf), "%u", vp->vp_integer);
+ len = strlen(a);
+ } else {
+ /* should never be truncated */
+ len = snprintf(buf, sizeof(buf), "%u", vp->vp_integer);
a = buf;
}
}
break;
case PW_TYPE_INTEGER64:
- snprintf(out, outlen, "%" PRIu64, vp->vp_integer64);
- return strlen(out);
+ return snprintf(out, outlen, "%" PRIu64, vp->vp_integer64);
case PW_TYPE_DATE:
t = vp->vp_date;
if (quote > 0) {
- len = strftime(buf, sizeof(buf) - 1, "%%%b %e %Y %H:%M:%S %Z%%",
- localtime_r(&t, &s_tm));
+ len = strftime(buf, sizeof(buf) - 1, "%%%b %e %Y %H:%M:%S %Z%%", localtime_r(&t, &s_tm));
buf[0] = (char) quote;
buf[len - 1] = (char) quote;
buf[len] = '\0';
} else {
- len = strftime(buf, sizeof(buf), "%b %e %Y %H:%M:%S %Z",
- localtime_r(&t, &s_tm));
+ len = strftime(buf, sizeof(buf), "%b %e %Y %H:%M:%S %Z", localtime_r(&t, &s_tm));
}
- if (len > 0) a = buf;
+ a = buf;
break;
case PW_TYPE_SIGNED: /* Damned code for 1 WiMAX attribute */
- snprintf(buf, sizeof(buf), "%d", vp->vp_signed);
+ len = snprintf(buf, sizeof(buf), "%d", vp->vp_signed);
a = buf;
break;
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
a = inet_ntop(AF_INET, &(vp->vp_ipaddr), buf, sizeof(buf));
+ len = strlen(buf);
break;
case PW_TYPE_ABINARY:
#ifdef WITH_ASCEND_BINARY
+
+ print_abinary(buf, sizeof(buf), vp, quote);
a = buf;
- print_abinary(vp, buf, sizeof(buf), quote);
+ len = strlen(buf);
break;
#else
/* FALL THROUGH */
#endif
case PW_TYPE_OCTETS:
- if (outlen <= (2 * (vp->length + 1))) return 0;
+ case PW_TYPE_TLV:
+ {
+ size_t max;
+
+ /* Return the number of bytes we would have written */
+ len = (vp->length * 2) + 2;
+ if (freespace <= 1) {
+ return len;
+ }
- strcpy(buf, "0x");
+ *out++ = '0';
+ freespace--;
- fr_bin2hex(buf + 2, vp->vp_octets, vp->length);
- a = buf;
+ if (freespace <= 1) {
+ *out = '\0';
+ return len;
+ }
+ *out++ = 'x';
+ freespace--;
+
+ if (freespace <= 2) {
+ *out = '\0';
+ return len;
+ }
+
+ /* Get maximum number of bytes we can encode given freespace */
+ max = ((freespace % 2) ? freespace - 1 : freespace - 2) / 2;
+ fr_bin2hex(out, vp->vp_octets, (vp->length > max) ? max : vp->length);
+
+ return len;
+ }
break;
case PW_TYPE_IFID:
a = ifid_ntoa(buf, sizeof(buf), vp->vp_ifid);
+ len = strlen(buf);
break;
- case PW_TYPE_IPV6ADDR:
+ case PW_TYPE_IPV6_ADDR:
a = inet_ntop(AF_INET6, &vp->vp_ipv6addr, buf, sizeof(buf));
+ len = strlen(buf);
break;
- case PW_TYPE_IPV6PREFIX:
+ case PW_TYPE_IPV6_PREFIX:
{
struct in6_addr addr;
a = inet_ntop(AF_INET6, &addr, buf, sizeof(buf));
if (a) {
- char *p = buf + strlen(buf);
- snprintf(p, buf + sizeof(buf) - p - 1, "/%u",
- (unsigned int) vp->vp_ipv6prefix[1]);
+ char *p = buf;
+
+ len = strlen(buf);
+ p += len;
+ len += snprintf(p, sizeof(buf) - len, "/%u", (unsigned int) vp->vp_ipv6prefix[1]);
}
}
break;
- case PW_TYPE_IPV4PREFIX:
+ case PW_TYPE_IPV4_PREFIX:
{
struct in_addr addr;
a = inet_ntop(AF_INET, &addr, buf, sizeof(buf));
if (a) {
- char *p = buf + strlen(buf);
- snprintf(p, buf + sizeof(buf) - p - 1, "/%u",
- (unsigned int) (vp->vp_ipv4prefix[1] & 0x3f));
+ char *p = buf;
+
+ len = strlen(buf);
+ p += len;
+ len += snprintf(p, sizeof(buf) - len, "/%u", (unsigned int) (vp->vp_ipv4prefix[1] & 0x3f));
}
}
break;
case PW_TYPE_ETHERNET:
- snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
- vp->vp_ether[0], vp->vp_ether[1],
- vp->vp_ether[2], vp->vp_ether[3],
- vp->vp_ether[4], vp->vp_ether[5]);
- a = buf;
- break;
-
- case PW_TYPE_TLV:
- if (outlen <= (2 * (vp->length + 1))) return 0;
-
- strcpy(buf, "0x");
-
- fr_bin2hex(buf + 2, vp->vp_tlv, vp->length);
- a = buf;
- break;
+ return snprintf(out, outlen, "%02x:%02x:%02x:%02x:%02x:%02x",
+ vp->vp_ether[0], vp->vp_ether[1],
+ vp->vp_ether[2], vp->vp_ether[3],
+ vp->vp_ether[4], vp->vp_ether[5]);
default:
a = "UNKNOWN-TYPE";
+ len = strlen(a);
break;
}
- if (a != NULL) strlcpy(out, a, outlen);
+ if (a) strlcpy(out, a, outlen);
- return strlen(out);
+ return len; /* Return the number of bytes we would of written (for truncation detection) */
}
-
-char *vp_aprinttype(TALLOC_CTX *ctx, PW_TYPE type)
+char *vp_aprint_type(TALLOC_CTX *ctx, PW_TYPE type)
{
switch (type) {
case PW_TYPE_STRING :
- return talloc_strdup(ctx, "_");
+ return talloc_typed_strdup(ctx, "_");
case PW_TYPE_INTEGER64:
case PW_TYPE_SIGNED:
case PW_TYPE_SHORT:
case PW_TYPE_INTEGER:
case PW_TYPE_DATE :
- return talloc_strdup(ctx, "0");
+ return talloc_typed_strdup(ctx, "0");
- case PW_TYPE_IPADDR :
- return talloc_strdup(ctx, "?.?.?.?");
+ case PW_TYPE_IPV4_ADDR :
+ return talloc_typed_strdup(ctx, "?.?.?.?");
- case PW_TYPE_IPV4PREFIX:
- return talloc_strdup(ctx, "?.?.?.?/?");
+ case PW_TYPE_IPV4_PREFIX:
+ return talloc_typed_strdup(ctx, "?.?.?.?/?");
- case PW_TYPE_IPV6ADDR:
- return talloc_strdup(ctx, "[:?:]");
+ case PW_TYPE_IPV6_ADDR:
+ return talloc_typed_strdup(ctx, "[:?:]");
- case PW_TYPE_IPV6PREFIX:
- return talloc_strdup(ctx, "[:?:]/?");
+ case PW_TYPE_IPV6_PREFIX:
+ return talloc_typed_strdup(ctx, "[:?:]/?");
case PW_TYPE_OCTETS:
- return talloc_strdup(ctx, "0x??");
+ return talloc_typed_strdup(ctx, "??");
case PW_TYPE_ETHERNET:
- return talloc_strdup(ctx, "??:??:??:??:??:??:??:??");
+ return talloc_typed_strdup(ctx, "??:??:??:??:??:??:??:??");
#ifdef WITH_ASCEND_BINARY
case PW_TYPE_ABINARY:
- return talloc_strdup(ctx, "??");
+ return talloc_typed_strdup(ctx, "??");
#endif
default :
break;
}
- return talloc_strdup(ctx, "<UNKNOWN-TYPE>");
-}
-
-/*
- * vp_prints_value for talloc
- */
-char *vp_aprint(TALLOC_CTX *ctx, VALUE_PAIR const *vp)
-{
- char *p;
-
- switch (vp->da->type) {
- case PW_TYPE_STRING:
- /*
- * FIXME: deal with \r\n" ??
- */
- p = talloc_strdup(ctx, vp->vp_strvalue);
- break;
-
- case PW_TYPE_BYTE:
- case PW_TYPE_SHORT:
- case PW_TYPE_INTEGER:
- {
- DICT_VALUE *dv;
-
- dv = dict_valbyattr(vp->da->attr, vp->da->vendor,
- vp->vp_integer);
- if (dv) {
- p = talloc_strdup(ctx, dv->name);
- } else {
- p = talloc_asprintf(ctx, "%u", vp->vp_integer);
- }
- }
- break;
-
- case PW_TYPE_SIGNED:
- p = talloc_asprintf(ctx, "%d", vp->vp_signed);
- break;
-
- case PW_TYPE_INTEGER64:
- p = talloc_asprintf(ctx, "%" PRIu64 , vp->vp_integer64);
- break;
-
- case PW_TYPE_ETHERNET:
- p = talloc_asprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
- vp->vp_ether[0], vp->vp_ether[1],
- vp->vp_ether[2], vp->vp_ether[3],
- vp->vp_ether[4], vp->vp_ether[5]);
- break;
-
- case PW_TYPE_ABINARY:
-#ifdef WITH_ASCEND_BINARY
- p = talloc_array(ctx, char, 128);
- if (!p) return NULL;
- print_abinary(vp, p, 128, 0);
- break;
-#else
- /* FALL THROUGH */
-#endif
-
- case PW_TYPE_OCTETS:
- p = talloc_array(ctx, char, 3 + vp->length * 2);
- if (!p) return NULL;
- memcpy(p, "0x", 2);
- fr_bin2hex(p + 2, vp->vp_octets, vp->length);
- break;
-
- case PW_TYPE_DATE:
- {
- time_t t;
- struct tm s_tm;
-
- t = vp->vp_date;
-
- p = talloc_array(ctx, char, 64);
- strftime(p, 64, "%b %e %Y %H:%M:%S %Z",
- localtime_r(&t, &s_tm));
- break;
- }
-
- case PW_TYPE_IPADDR:
- p = talloc_asprintf(ctx, "%u.%u.%u.%u",
- vp->vp_ipv4prefix[0], /* network byte order */
- vp->vp_ipv4prefix[1],
- vp->vp_ipv4prefix[2],
- vp->vp_ipv4prefix[3]);
- break;
-
- case PW_TYPE_IPV4PREFIX:
- p = talloc_asprintf(ctx, "%u.%u.%u.%u/%u",
- vp->vp_ipv4prefix[2],
- vp->vp_ipv4prefix[3],
- vp->vp_ipv4prefix[4],
- vp->vp_ipv4prefix[5],
- vp->vp_ipv4prefix[1] & 0x3f);
- break;
-
- case PW_TYPE_IPV6ADDR:
- p = talloc_asprintf(ctx, "%x:%x:%x:%x:%x:%x:%x:%x",
- (vp->vp_ipv6addr.s6_addr[0] << 8) | vp->vp_ipv6addr.s6_addr[1],
- (vp->vp_ipv6addr.s6_addr[2] << 8) | vp->vp_ipv6addr.s6_addr[3],
- (vp->vp_ipv6addr.s6_addr[4] << 8) | vp->vp_ipv6addr.s6_addr[5],
- (vp->vp_ipv6addr.s6_addr[6] << 8) | vp->vp_ipv6addr.s6_addr[7],
- (vp->vp_ipv6addr.s6_addr[8] << 8) | vp->vp_ipv6addr.s6_addr[9],
- (vp->vp_ipv6addr.s6_addr[10] << 8) | vp->vp_ipv6addr.s6_addr[11],
- (vp->vp_ipv6addr.s6_addr[12] << 8) | vp->vp_ipv6addr.s6_addr[13],
- (vp->vp_ipv6addr.s6_addr[14] << 8) | vp->vp_ipv6addr.s6_addr[15]);
- break;
-
- case PW_TYPE_IPV6PREFIX:
- p = talloc_asprintf(ctx, "%x:%x:%x:%x:%x:%x:%x:%x/%u",
- (vp->vp_ipv6prefix[2] << 8) | vp->vp_ipv6prefix[3],
- (vp->vp_ipv6prefix[4] << 8) | vp->vp_ipv6prefix[5],
- (vp->vp_ipv6prefix[6] << 8) | vp->vp_ipv6prefix[7],
- (vp->vp_ipv6prefix[8] << 8) | vp->vp_ipv6prefix[9],
- (vp->vp_ipv6prefix[10] << 8) | vp->vp_ipv6prefix[11],
- (vp->vp_ipv6prefix[12] << 8) | vp->vp_ipv6prefix[13],
- (vp->vp_ipv6prefix[14] << 8) | vp->vp_ipv6prefix[15],
- (vp->vp_ipv6prefix[16] << 8) | vp->vp_ipv6prefix[17],
- vp->vp_ipv6prefix[2]);
- break;
-
- case PW_TYPE_IFID:
- p = talloc_asprintf(ctx, "%x:%x:%x:%x",
- (vp->vp_ifid[0] << 8) | vp->vp_ifid[1],
- (vp->vp_ifid[2] << 8) | vp->vp_ifid[3],
- (vp->vp_ifid[4] << 8) | vp->vp_ifid[5],
- (vp->vp_ifid[6] << 8) | vp->vp_ifid[7]);
- break;
-
- default:
- p = NULL;
- break;
- }
-
- return p;
+ return talloc_typed_strdup(ctx, "<UNKNOWN-TYPE>");
}
-
/** Prints attribute values escaped suitably for use as JSON values
*
* Returns < 0 if the buffer may be (or have been) too small to write the encoded
*/
size_t vp_prints_value_json(char *out, size_t outlen, VALUE_PAIR const *vp)
{
- char *start = out;
char const *q;
size_t len, freespace = outlen;
case PW_TYPE_SHORT:
if (vp->da->flags.has_value) break;
- len = snprintf(out, freespace, "%u", vp->vp_integer);
- return len;
+ return snprintf(out, freespace, "%u", vp->vp_integer);
case PW_TYPE_SIGNED:
- len = snprintf(out, freespace, "%d", vp->vp_signed);
- return len;
+ return snprintf(out, freespace, "%d", vp->vp_signed);
default:
break;
}
}
- if (freespace < 2) return -1;
+ /* Indicate truncation */
+ if (freespace < 2) return outlen + 1;
*out++ = '"';
freespace--;
switch (vp->da->type) {
case PW_TYPE_STRING:
for (q = vp->vp_strvalue; q < vp->vp_strvalue + vp->length; q++) {
- if (freespace < 3) return -1;
+ /* Indicate truncation */
+ if (freespace < 3) return outlen + 1;
if (*q == '"') {
*out++ = '\\';
break;
default:
len = snprintf(out, freespace, "u%04X", *q);
- if (len >= freespace) return outlen;
+ if (is_truncated(len, freespace)) return (outlen - freespace) + len;
out += len;
freespace -= len;
}
default:
len = vp_prints_value(out, freespace, vp, 0);
- if (len >= freespace) return outlen;
+ if (is_truncated(len, freespace)) return (outlen - freespace) + len;
out += len;
freespace -= len;
break;
}
- if (freespace < 2) return outlen;
+ /* Indicate truncation */
+ if (freespace < 2) return outlen + 1;
*out++ = '"';
+ freespace--;
*out = '\0'; // We don't increment out, because the nul byte should not be included in the length
- return out - start;
+ return outlen - freespace;
}
/*
extern int fr_attr_shift[];
extern int fr_attr_mask[];
-/** Print an attribute OID (does not include vendor)
- *
- * @param out Where to write the string.
- * @param outlen Lenth of output buffer.
- * @param attr id.
- * @param dv_type Type of dictionary value.
- * @return the length of data written to out, or a value >= outlen on truncation.
- */
-static size_t vp_print_attr_oid(char *out, size_t outlen, unsigned int attr, int dv_type)
-{
- int nest;
- char *start = out;
- size_t len, freespace = outlen;
-
- switch (dv_type) {
- case 4:
- return snprintf(out, freespace, "%u", attr);
-
- case 2:
- return snprintf(out, freespace, "%u", attr & 0xffff);
-
- default:
- case 1:
- len = snprintf(out, freespace, "%u", attr & 0xff);
- if (len >= freespace) return outlen;
- out += len;
- freespace -= len;
- break;
- }
-
- if ((attr >> 8) == 0) return out - start;
-
- for (nest = 1; nest <= fr_attr_max_tlv; nest++) {
- if (((attr >> fr_attr_shift[nest]) & fr_attr_mask[nest]) == 0) break;
-
- len = snprintf(out, freespace, ".%u", (attr >> fr_attr_shift[nest]) & fr_attr_mask[nest]);
- if (len >= freespace) return outlen;
- out += freespace;
- freespace -= len;
- }
-
- return out - start;
-}
-
-/** Print the names of attributes which are not in the dictionaries
- *
- * Print name for an unknown attribute in the format:
-@verbatim
- Attr-<vendor id>-<attribute oid>
-@endverbatim
- * to a string.
- *
- * @param out Where to write the string.
- * @param outlen Lenth of output buffer.
- * @param attr id.
- * @param vendor id.
- * @return the length of data written to out, or a value >= outlen on truncation.
- */
-size_t vp_print_name(char *out, size_t outlen, unsigned int attr, unsigned int vendor)
-{
- int dv_type = 1;
- char *start = out;
- size_t len, freespace = outlen;
-
- if (!out) return 0;
-
- len = snprintf(out, freespace, "Attr-");
- if (len >= freespace) return outlen;
- out += len;
- freespace -= len;
-
- if (vendor > FR_MAX_VENDOR) {
- len = snprintf(out, freespace, "%u.", vendor / FR_MAX_VENDOR);
- if (len >= freespace) return outlen;
- out += len;
- freespace -= len;
-
- vendor &= (FR_MAX_VENDOR) - 1;
- }
-
- if (vendor) {
- DICT_VENDOR *dv;
-
- dv = dict_vendorbyvalue(vendor);
- if (dv) {
- dv_type = dv->type;
- }
-
- len = snprintf(out, freespace, "26.%u.", vendor);
- if (len >= freespace) return outlen;
- out += len;
- freespace -= len;
- }
-
- len = vp_print_attr_oid(out, freespace, attr, dv_type);
- if (len >= freespace) return outlen;
- out += len;
-
- return out - start;
-}
-
/** Print one attribute and value to a string
*
size_t vp_prints(char *out, size_t outlen, VALUE_PAIR const *vp)
{
char const *token = NULL;
- char *start = out;
size_t len, freespace = outlen;
if (!out) return 0;
token = "<INVALID-TOKEN>";
}
- if(vp->da->flags.has_tag) {
+ if (vp->da->flags.has_tag) {
len = snprintf(out, freespace, "%s:%d %s ", vp->da->name, vp->tag, token);
} else {
len = snprintf(out, freespace, "%s %s ", vp->da->name, token);
}
- if (len >= freespace) return outlen;
+
+ if (is_truncated(len, freespace)) return len;
out += len;
freespace -= len;
len = vp_prints_value(out, freespace, vp, '\'');
- if (len >= freespace) return outlen;
- out += len;
+ if (is_truncated(len, freespace)) return (outlen - freespace) + len;
+ freespace -= len;
- return out - start;
+ return (outlen - freespace);
}
-
/** Print one attribute and value to FP
*
* Complete string with '\\t' and '\\n' is written to buffer before printing to
char *p = buf;
size_t len;
+ VERIFY_VP(vp);
+
*p++ = '\t';
len = vp_prints(p, sizeof(buf) - 1, vp);
if (!len) {
void vp_printlist(FILE *fp, VALUE_PAIR const *vp)
{
vp_cursor_t cursor;
- for (vp = paircursorc(&cursor, &vp); vp; vp = pairnext(&cursor)) {
+ for (vp = fr_cursor_init(&cursor, &vp); vp; vp = fr_cursor_next(&cursor)) {
vp_print(fp, vp);
}
}
+
+/*
+ * vp_prints_value for talloc
+ */
+char *vp_aprint_value(TALLOC_CTX *ctx, VALUE_PAIR const *vp)
+{
+ char *p;
+
+ switch (vp->da->type) {
+ case PW_TYPE_STRING:
+ {
+ size_t len, ret;
+
+ /* Gets us the size of the buffer we need to alloc */
+ len = fr_print_string_len(vp->vp_strvalue, vp->length);
+ p = talloc_array(ctx, char, len + 1); /* +1 for '\0' */
+ if (!p) return NULL;
+
+ ret = fr_print_string(vp->vp_strvalue, vp->length, p, len + 1);
+ if (!fr_assert(ret == len)) {
+ talloc_free(p);
+ return NULL;
+ }
+ break;
+ }
+
+ case PW_TYPE_BYTE:
+ case PW_TYPE_SHORT:
+ case PW_TYPE_INTEGER:
+ {
+ DICT_VALUE *dv;
+
+ dv = dict_valbyattr(vp->da->attr, vp->da->vendor,
+ vp->vp_integer);
+ if (dv) {
+ p = talloc_typed_strdup(ctx, dv->name);
+ } else {
+ p = talloc_typed_asprintf(ctx, "%u", vp->vp_integer);
+ }
+ }
+ break;
+
+ case PW_TYPE_SIGNED:
+ p = talloc_typed_asprintf(ctx, "%d", vp->vp_signed);
+ break;
+
+ case PW_TYPE_INTEGER64:
+ p = talloc_typed_asprintf(ctx, "%" PRIu64 , vp->vp_integer64);
+ break;
+
+ case PW_TYPE_ETHERNET:
+ p = talloc_typed_asprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
+ vp->vp_ether[0], vp->vp_ether[1],
+ vp->vp_ether[2], vp->vp_ether[3],
+ vp->vp_ether[4], vp->vp_ether[5]);
+ break;
+
+ case PW_TYPE_ABINARY:
+#ifdef WITH_ASCEND_BINARY
+ p = talloc_array(ctx, char, 128);
+ if (!p) return NULL;
+ print_abinary(p, 128, vp, 0);
+ break;
+#else
+ /* FALL THROUGH */
+#endif
+
+ case PW_TYPE_OCTETS:
+ p = talloc_array(ctx, char, 1 + vp->length * 2);
+ if (!p) return NULL;
+ fr_bin2hex(p, vp->vp_octets, vp->length);
+ break;
+
+ case PW_TYPE_DATE:
+ {
+ time_t t;
+ struct tm s_tm;
+
+ t = vp->vp_date;
+
+ p = talloc_array(ctx, char, 64);
+ strftime(p, 64, "%b %e %Y %H:%M:%S %Z",
+ localtime_r(&t, &s_tm));
+ break;
+ }
+
+ /*
+ * We need to use the proper inet_ntop functions for IP
+ * addresses, else the output might not match output of
+ * other functions, which makes testing difficult.
+ *
+ * An example is tunnelled ipv4 in ipv6 addresses.
+ */
+ case PW_TYPE_IPV4_ADDR:
+ case PW_TYPE_IPV4_PREFIX:
+ {
+ char buff[INET_ADDRSTRLEN + 4]; // + /prefix
+
+ buff[0] = '\0';
+ vp_prints_value(buff, sizeof(buff), vp, 0);
+
+ p = talloc_typed_strdup(ctx, buff);
+ }
+ break;
+
+ case PW_TYPE_IPV6_ADDR:
+ case PW_TYPE_IPV6_PREFIX:
+ {
+ char buff[INET6_ADDRSTRLEN + 4]; // + /prefix
+
+ buff[0] = '\0';
+ vp_prints_value(buff, sizeof(buff), vp, 0);
+
+ p = talloc_typed_strdup(ctx, buff);
+ }
+ break;
+
+ case PW_TYPE_IFID:
+ p = talloc_typed_asprintf(ctx, "%x:%x:%x:%x",
+ (vp->vp_ifid[0] << 8) | vp->vp_ifid[1],
+ (vp->vp_ifid[2] << 8) | vp->vp_ifid[3],
+ (vp->vp_ifid[4] << 8) | vp->vp_ifid[5],
+ (vp->vp_ifid[6] << 8) | vp->vp_ifid[7]);
+ break;
+
+ default:
+ p = NULL;
+ break;
+ }
+
+ return p;
+}
+
+/** Print one attribute and value to a string
+ *
+ * Print a VALUE_PAIR in the format:
+@verbatim
+ <attribute_name>[:tag] <op> <value>
+@endverbatim
+ * to a string.
+ *
+ * @param ctx to allocate string in.
+ * @param vp to print.
+ * @return a talloced buffer with the attribute operator and value.
+ */
+char *vp_aprint(TALLOC_CTX *ctx, VALUE_PAIR const *vp)
+{
+ char const *token = NULL;
+ char *pair, *value;
+
+ if (!vp || !vp->da) return 0;
+
+ VERIFY_VP(vp);
+
+ if ((vp->op > T_OP_INVALID) && (vp->op < T_TOKEN_LAST)) {
+ token = vp_tokens[vp->op];
+ } else {
+ token = "<INVALID-TOKEN>";
+ }
+
+ value = vp_aprint_value(ctx, vp);
+ pair = vp->da->flags.has_tag ?
+ talloc_asprintf(ctx, "%s:%d %s %s", vp->da->name, vp->tag, token, value) :
+ talloc_asprintf(ctx, "%s %s %s", vp->da->name, token, value);
+ talloc_free(value);
+
+ return pair;
+}
+
+
* is unsigned, and the attacker can use resources on the server,
* even if the end request is rejected.
*/
-int fr_max_attributes = 0;
+uint32_t fr_max_attributes = 0;
FILE *fr_log_fp = NULL;
typedef struct radius_packet_t {
static uint8_t nullvector[AUTH_VECTOR_LEN] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* for CoA decode */
char const *fr_packet_codes[FR_MAX_PACKET_CODE] = {
- "",
+ "", //!< 0
"Access-Request",
"Access-Accept",
"Access-Reject",
"Password-Request",
"Password-Accept",
"Password-Reject",
- "Accounting-Message",
+ "Accounting-Message", //!< 10
"Access-Challenge",
"Status-Server",
"Status-Client",
"17",
"18",
"19",
- "20",
+ "20", //!< 20
"Resource-Free-Request",
"Resource-Free-Response",
"Resource-Query-Request",
"NAS-Reboot-Response",
"28",
"Next-Passcode",
- "New-Pin",
+ "New-Pin", //!< 30
"Terminate-Session",
"Password-Expired",
"Event-Request",
"37",
"38",
"39",
- "Disconnect-Request",
+ "Disconnect-Request", //!< 40
"Disconnect-ACK",
"Disconnect-NAK",
"CoA-Request",
"48",
"49",
"IP-Address-Allocate",
- "IP-Address-Release"
+ "IP-Address-Release", //!< 50
};
*/
static int rad_sendto(int sockfd, void *data, size_t data_len, int flags,
#ifdef WITH_UDPFROMTO
- fr_ipaddr_t *src_ipaddr, int src_port,
+ fr_ipaddr_t *src_ipaddr, uint16_t src_port,
#else
- UNUSED fr_ipaddr_t *src_ipaddr, UNUSED int src_port,
+ UNUSED fr_ipaddr_t *src_ipaddr, UNUSED uint16_t src_port,
#endif
- fr_ipaddr_t *dst_ipaddr, int dst_port)
+ fr_ipaddr_t *dst_ipaddr, uint16_t dst_port)
{
int rcode;
struct sockaddr_storage dst;
done:
#endif
if (rcode < 0) {
- DEBUG("rad_send() failed: %s\n", strerror(errno));
+ fr_strerror_printf("sendto failed: %s", fr_syserror(errno));
}
return rcode;
}
-ssize_t rad_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, int *src_port,
- int *code)
+ssize_t rad_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, int *code)
{
ssize_t data_len, packet_len;
uint8_t header[4];
ssize_t data_len;
uint8_t header[4];
size_t len;
- int port;
+ uint16_t port;
memset(&src, 0, sizeof_src);
memset(&dst, 0, sizeof_dst);
break;
case PW_TYPE_IFID:
- case PW_TYPE_IPADDR:
- case PW_TYPE_IPV6ADDR:
- case PW_TYPE_IPV6PREFIX:
- case PW_TYPE_IPV4PREFIX:
+ case PW_TYPE_IPV4_ADDR:
+ case PW_TYPE_IPV6_ADDR:
+ case PW_TYPE_IPV6_PREFIX:
+ case PW_TYPE_IPV4_PREFIX:
case PW_TYPE_ABINARY:
+ case PW_TYPE_ETHERNET: /* just in case */
data = (uint8_t const *) &vp->data;
break;
case PW_TYPE_BYTE:
len = 1; /* just in case */
- array[0] = vp->vp_integer & 0xff;
+ array[0] = vp->vp_byte;
data = array;
break;
case PW_TYPE_SHORT:
len = 2; /* just in case */
- array[0] = (vp->vp_integer >> 8) & 0xff;
- array[1] = vp->vp_integer & 0xff;
+ array[0] = (vp->vp_short >> 8) & 0xff;
+ array[1] = vp->vp_short & 0xff;
data = array;
break;
}
default: /* unknown type: ignore it */
- fr_strerror_printf("ERROR: Unknown attribute type %d",
- vp->da->type);
+ fr_strerror_printf("ERROR: Unknown attribute type %d", vp->da->type);
return -1;
}
if (room < (18 + lvalue)) return 0;
switch (packet->code) {
- case PW_AUTHENTICATION_ACK:
- case PW_AUTHENTICATION_REJECT:
- case PW_ACCESS_CHALLENGE:
+ case PW_CODE_AUTHENTICATION_ACK:
+ case PW_CODE_AUTHENTICATION_REJECT:
+ case PW_CODE_ACCESS_CHALLENGE:
default:
if (!original) {
fr_strerror_printf("ERROR: No request packet, cannot encrypt %s attribute in the vp.", vp->da->name);
return -1;
}
- if (lvalue) ptr[0] = vp->tag;
+ if (lvalue) ptr[0] = TAG_VALID(vp->tag) ? vp->tag : TAG_NONE;
make_tunnel_passwd(ptr + lvalue, &len, data, len,
room - lvalue,
secret, original->vector);
break;
- case PW_ACCOUNTING_REQUEST:
- case PW_DISCONNECT_REQUEST:
- case PW_COA_REQUEST:
- ptr[0] = vp->tag;
+ case PW_CODE_ACCOUNTING_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ case PW_CODE_COA_REQUEST:
+ ptr[0] = TAG_VALID(vp->tag) ? vp->tag : TAG_NONE;
make_tunnel_passwd(ptr + 1, &len, data, len - 1, room,
secret, packet->vector);
break;
*/
uint64_t data[MAX_PACKET_LEN / sizeof(uint64_t)];
- if ((packet->code > 0) && (packet->code < FR_MAX_PACKET_CODE)) {
+ if (is_radius_code(packet->code)) {
what = fr_packet_codes[packet->code];
} else {
what = "Reply";
}
- DEBUG("Sending %s of id %d from %s port %u to %s port %u\n",
+ DEBUG("Sending %s Id %d from %s:%u to %s:%u\n",
what, packet->id,
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
* Double-check some things based on packet code.
*/
switch (packet->code) {
- case PW_AUTHENTICATION_ACK:
- case PW_AUTHENTICATION_REJECT:
- case PW_ACCESS_CHALLENGE:
+ case PW_CODE_AUTHENTICATION_ACK:
+ case PW_CODE_AUTHENTICATION_REJECT:
+ case PW_CODE_ACCESS_CHALLENGE:
if (!original) {
- fr_strerror_printf("ERROR: Cannot sign response packet without a request packet.");
+ fr_strerror_printf("ERROR: Cannot sign response packet without a request packet");
return -1;
}
break;
/*
* These packet vectors start off as all zero.
*/
- case PW_ACCOUNTING_REQUEST:
- case PW_DISCONNECT_REQUEST:
- case PW_COA_REQUEST:
+ case PW_CODE_ACCOUNTING_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ case PW_CODE_COA_REQUEST:
memset(packet->vector, 0, sizeof(packet->vector));
break;
* It wasn't assigned an Id, this is bad!
*/
if (packet->id < 0) {
- fr_strerror_printf("ERROR: RADIUS packets must be assigned an Id.");
+ fr_strerror_printf("ERROR: RADIUS packets must be assigned an Id");
return -1;
}
uint8_t calc_auth_vector[AUTH_VECTOR_LEN];
switch (packet->code) {
- case PW_ACCOUNTING_RESPONSE:
- if (original && original->code == PW_STATUS_SERVER) {
+ case PW_CODE_ACCOUNTING_RESPONSE:
+ if (original && original->code == PW_CODE_STATUS_SERVER) {
goto do_ack;
}
- case PW_ACCOUNTING_REQUEST:
- case PW_DISCONNECT_REQUEST:
- case PW_DISCONNECT_ACK:
- case PW_DISCONNECT_NAK:
- case PW_COA_REQUEST:
- case PW_COA_ACK:
- case PW_COA_NAK:
+ case PW_CODE_ACCOUNTING_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ case PW_CODE_DISCONNECT_ACK:
+ case PW_CODE_DISCONNECT_NAK:
+ case PW_CODE_COA_REQUEST:
+ case PW_CODE_COA_ACK:
memset(hdr->vector, 0, AUTH_VECTOR_LEN);
break;
do_ack:
- case PW_AUTHENTICATION_ACK:
- case PW_AUTHENTICATION_REJECT:
- case PW_ACCESS_CHALLENGE:
+ case PW_CODE_AUTHENTICATION_ACK:
+ case PW_CODE_AUTHENTICATION_REJECT:
+ case PW_CODE_ACCESS_CHALLENGE:
if (!original) {
- fr_strerror_printf("ERROR: Cannot sign response packet without a request packet.");
+ fr_strerror_printf("ERROR: Cannot sign response packet without a request packet");
return -1;
}
memcpy(hdr->vector, original->vector,
* Request packets are not signed, bur
* have a random authentication vector.
*/
- case PW_AUTHENTICATION_REQUEST:
- case PW_STATUS_SERVER:
+ case PW_CODE_AUTHENTICATION_REQUEST:
+ case PW_CODE_STATUS_SERVER:
break;
/*
return 0;
}
- if ((packet->code > 0) && (packet->code < FR_MAX_PACKET_CODE)) {
+ if (is_radius_code(packet->code)) {
what = fr_packet_codes[packet->code];
} else {
what = "Reply";
* the VP list again only for debugging.
*/
} else if (fr_debug_flag) {
- DEBUG("Sending %s of id %d from %s port %u to %s port %u\n", what,
- packet->id,
- inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr,
- ip_src_buffer, sizeof(ip_src_buffer)),
+ DEBUG("Sending %s Id %d from %s:%u to %s:%u\n", what,
+ packet->id,
+ inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr,
+ ip_src_buffer, sizeof(ip_src_buffer)),
packet->src_port,
inet_ntop(packet->dst_ipaddr.af, &packet->dst_ipaddr.ipaddr,
ip_dst_buffer, sizeof(ip_dst_buffer)),
if ((fr_debug_flag > 3) && fr_log_fp) rad_print_hex(packet);
#endif
+#ifdef WITH_TCP
+ /*
+ * If the socket is TCP, call write(). Calling sendto()
+ * is allowed on some platforms, but it's not nice. Even
+ * worse, if UDPFROMTO is defined, we *can't* use it on
+ * TCP sockets. So... just call write().
+ */
+ if (packet->proto == IPPROTO_TCP) {
+ ssize_t rcode;
+
+ rcode = write(packet->sockfd, packet->data, packet->data_len);
+ if (rcode >= 0) return rcode;
+
+ fr_strerror_printf("sendto failed: %s", fr_syserror(errno));
+ return -1;
+ }
+#endif
+
/*
* And send it on it's way.
*/
}
-/**
- * @brief See if the data pointed to by PTR is a valid RADIUS packet.
+/** See if the data pointed to by PTR is a valid RADIUS packet.
+ *
+ * Packet is not 'const * const' because we may update data_len, if there's more data
+ * in the UDP packet than in the RADIUS packet.
*
- * packet is not 'const * const' because we may update data_len,
- * if there's more data in the UDP packet than in the RADIUS packet.
+ * @param packet to check
+ * @param flags to control decoding
+ * @param reason if not NULL, will have the failure reason written to where it points.
+ * @return bool, true on success, false on failure.
*/
-int rad_packet_ok(RADIUS_PACKET *packet, int flags)
+bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
{
uint8_t *attr;
size_t totallen;
int count;
radius_packet_t *hdr;
char host_ipaddr[128];
- int require_ma = 0;
- int seen_ma = 0;
- int num_attributes;
+ bool require_ma = false;
+ bool seen_ma = false;
+ uint32_t num_attributes;
+ decode_fail_t failure = DECODE_FAIL_NONE;
/*
* Check for packets smaller than the packet header.
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
packet->data_len, AUTH_HDR_LEN);
- return 0;
+ failure = DECODE_FAIL_MIN_LENGTH_PACKET;
+ goto finish;
}
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
hdr->code);
- return 0;
+ failure = DECODE_FAIL_UNKNOWN_PACKET_CODE;
+ goto finish;
}
/*
* Message-Authenticator is required in Status-Server
* packets, otherwise they can be trivially forged.
*/
- if (hdr->code == PW_STATUS_SERVER) require_ma = 1;
+ if (hdr->code == PW_CODE_STATUS_SERVER) require_ma = true;
/*
* It's also required if the caller asks for it.
*/
- if (flags) require_ma = 1;
+ if (flags) require_ma = true;
/*
* Repeat the length checks. This time, instead of
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
totallen, AUTH_HDR_LEN);
- return 0;
+ failure = DECODE_FAIL_MIN_LENGTH_FIELD;
+ goto finish;
}
/*
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
packet->data_len, totallen);
- return 0;
+ failure = DECODE_FAIL_MIN_LENGTH_MISMATCH;
+ goto finish;
}
/*
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)));
- return 0;
+ failure = DECODE_FAIL_HEADER_OVERFLOW;
+ goto finish;
}
/*
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)));
- return 0;
+ failure = DECODE_FAIL_INVALID_ATTRIBUTE;
+ goto finish;
}
/*
* Attributes are at LEAST as long as the ID & length
* fields. Anything shorter is an invalid attribute.
*/
- if (attr[1] < 2) {
+ if (attr[1] < 2) {
fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: attribute %u too short",
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
attr[0]);
- return 0;
+ failure = DECODE_FAIL_ATTRIBUTE_TOO_SHORT;
+ goto finish;
}
/*
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
attr[0]);
- return 0;
+ failure = DECODE_FAIL_ATTRIBUTE_OVERFLOW;
+ goto finish;
}
/*
* a Message-Authenticator.
*/
case PW_EAP_MESSAGE:
- require_ma = 1;
+ require_ma = true;
break;
case PW_MESSAGE_AUTHENTICATOR:
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
attr[1] - 2);
- return 0;
+ failure = DECODE_FAIL_MA_INVALID_LENGTH;
+ goto finish;
}
- seen_ma = 1;
+ seen_ma = true;
break;
}
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)));
- return 0;
+ failure = DECODE_FAIL_ATTRIBUTE_UNDERFLOW;
+ goto finish;
}
/*
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
num_attributes, fr_max_attributes);
- return 0;
+ failure = DECODE_FAIL_TOO_MANY_ATTRIBUTES;
+ goto finish;
}
/*
* Similarly, Status-Server packets MUST contain
* Message-Authenticator attributes.
*/
- if (require_ma && ! seen_ma) {
+ if (require_ma && !seen_ma) {
fr_strerror_printf("WARNING: Insecure packet from host %s: Packet does not contain required Message-Authenticator attribute",
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)));
- return 0;
+ failure = DECODE_FAIL_MA_MISSING;
+ goto finish;
}
/*
packet->id = hdr->id;
memcpy(packet->vector, hdr->vector, AUTH_VECTOR_LEN);
- return 1;
+
+ finish:
+
+ if (reason) {
+ *reason = failure;
+ }
+ return (failure == DECODE_FAIL_NONE);
}
* Check for socket errors.
*/
if (data_len < 0) {
- fr_strerror_printf("Error receiving packet: %s", strerror(errno));
+ fr_strerror_printf("Error receiving packet: %s", fr_syserror(errno));
/* packet->data is NULL */
rad_free(&packet);
return NULL;
* packet.
*/
if (packet->data_len > MAX_PACKET_LEN) {
- fr_strerror_printf("Discarding packet: Larger than RFC limitation of 4096 bytes.");
+ fr_strerror_printf("Discarding packet: Larger than RFC limitation of 4096 bytes");
/* packet->data is NULL */
rad_free(&packet);
return NULL;
* packet->data == NULL
*/
if ((packet->data_len == 0) || !packet->data) {
- fr_strerror_printf("Empty packet: Socket is not ready.");
+ fr_strerror_printf("Empty packet: Socket is not ready");
rad_free(&packet);
return NULL;
}
/*
* See if it's a well-formed RADIUS packet.
*/
- if (!rad_packet_ok(packet, flags)) {
+ if (!rad_packet_ok(packet, flags, NULL)) {
rad_free(&packet);
return NULL;
}
packet->vps = NULL;
if (fr_debug_flag) {
- char host_ipaddr[128];
+ char src_ipaddr[128];
+ char dst_ipaddr[128];
- if ((packet->code > 0) && (packet->code < FR_MAX_PACKET_CODE)) {
- DEBUG("rad_recv: %s packet from host %s port %d",
+ if (is_radius_code(packet->code)) {
+ DEBUG("Received %s Id %d from %s:%d to %s:%d length %d\n",
fr_packet_codes[packet->code],
+ packet->id,
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
- host_ipaddr, sizeof(host_ipaddr)),
- packet->src_port);
+ src_ipaddr, sizeof(src_ipaddr)),
+ packet->src_port,
+ inet_ntop(packet->dst_ipaddr.af,
+ &packet->dst_ipaddr.ipaddr,
+ dst_ipaddr, sizeof(dst_ipaddr)),
+ packet->dst_port,
+ (int) packet->data_len);
} else {
- DEBUG("rad_recv: Packet from host %s port %d code=%d",
+ DEBUG("Received code %d Id %d from %s:%d to %s:%d length %d\n",
+ packet->code,
+ packet->id,
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
- host_ipaddr, sizeof(host_ipaddr)),
+ src_ipaddr, sizeof(src_ipaddr)),
packet->src_port,
- packet->code);
+ inet_ntop(packet->dst_ipaddr.af,
+ &packet->dst_ipaddr.ipaddr,
+ dst_ipaddr, sizeof(dst_ipaddr)),
+ packet->dst_port,
+ (int) packet->data_len);
}
- DEBUG(", id=%d, length=%d\n",
- packet->id, (int) packet->data_len);
}
#ifndef NDEBUG
default:
break;
- case PW_ACCOUNTING_RESPONSE:
+ case PW_CODE_ACCOUNTING_RESPONSE:
if (original &&
- (original->code == PW_STATUS_SERVER)) {
+ (original->code == PW_CODE_STATUS_SERVER)) {
goto do_ack;
}
- case PW_ACCOUNTING_REQUEST:
- case PW_DISCONNECT_REQUEST:
- case PW_DISCONNECT_ACK:
- case PW_DISCONNECT_NAK:
- case PW_COA_REQUEST:
- case PW_COA_ACK:
- case PW_COA_NAK:
- memset(packet->data + 4, 0, AUTH_VECTOR_LEN);
+ case PW_CODE_ACCOUNTING_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ case PW_CODE_COA_REQUEST:
+ memset(packet->data + 4, 0, AUTH_VECTOR_LEN);
break;
do_ack:
- case PW_AUTHENTICATION_ACK:
- case PW_AUTHENTICATION_REJECT:
- case PW_ACCESS_CHALLENGE:
+ case PW_CODE_AUTHENTICATION_ACK:
+ case PW_CODE_AUTHENTICATION_REJECT:
+ case PW_CODE_ACCESS_CHALLENGE:
+ case PW_CODE_DISCONNECT_ACK:
+ case PW_CODE_DISCONNECT_NAK:
+ case PW_CODE_COA_ACK:
+ case PW_CODE_COA_NAK:
if (!original) {
- fr_strerror_printf("ERROR: Cannot validate Message-Authenticator in response packet without a request packet.");
+ fr_strerror_printf("ERROR: Cannot validate Message-Authenticator in response packet without a request packet");
return -1;
}
memcpy(packet->data + 4, original->vector, AUTH_VECTOR_LEN);
/*
* Calculate and/or verify Request or Response Authenticator.
*/
- switch(packet->code) {
+ switch (packet->code) {
int rcode;
char buffer[32];
- case PW_AUTHENTICATION_REQUEST:
- case PW_STATUS_SERVER:
+ case PW_CODE_AUTHENTICATION_REQUEST:
+ case PW_CODE_STATUS_SERVER:
/*
* The authentication vector is random
* nonsense, invented by the client.
*/
break;
- case PW_COA_REQUEST:
- case PW_DISCONNECT_REQUEST:
- case PW_ACCOUNTING_REQUEST:
+ case PW_CODE_COA_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ case PW_CODE_ACCOUNTING_REQUEST:
if (calc_acctdigest(packet, secret) > 1) {
fr_strerror_printf("Received %s packet "
"from client %s with invalid Request Authenticator! (Shared secret is incorrect.)",
break;
/* Verify the reply digest */
- case PW_AUTHENTICATION_ACK:
- case PW_AUTHENTICATION_REJECT:
- case PW_ACCESS_CHALLENGE:
- case PW_ACCOUNTING_RESPONSE:
- case PW_DISCONNECT_ACK:
- case PW_DISCONNECT_NAK:
- case PW_COA_ACK:
- case PW_COA_NAK:
+ case PW_CODE_AUTHENTICATION_ACK:
+ case PW_CODE_AUTHENTICATION_REJECT:
+ case PW_CODE_ACCESS_CHALLENGE:
+ case PW_CODE_ACCOUNTING_RESPONSE:
+ case PW_CODE_DISCONNECT_ACK:
+ case PW_CODE_DISCONNECT_NAK:
+ case PW_CODE_COA_ACK:
+ case PW_CODE_COA_NAK:
rcode = calc_replydigest(packet, original, secret);
if (rcode > 1) {
fr_strerror_printf("Received %s packet "
}
-static ssize_t data2vp(RADIUS_PACKET *packet,
- RADIUS_PACKET const *original,
- char const *secret,
- DICT_ATTR const *da, uint8_t const *start,
- size_t const attrlen, size_t const packetlen,
- VALUE_PAIR **pvp);
-
/**
* @brief convert a "concatenated" attribute to one long VP.
*/
*
* @return -1 on error, or "length".
*/
-static ssize_t data2vp(RADIUS_PACKET *packet,
- RADIUS_PACKET const *original,
- char const *secret,
- DICT_ATTR const *da, uint8_t const *start,
- size_t const attrlen, size_t const packetlen,
- VALUE_PAIR **pvp)
+ssize_t data2vp(RADIUS_PACKET *packet,
+ RADIUS_PACKET const *original,
+ char const *secret,
+ DICT_ATTR const *da, uint8_t const *start,
+ size_t const attrlen, size_t const packetlen,
+ VALUE_PAIR **pvp)
{
- int tag = 0;
+ int8_t tag = TAG_NONE;
size_t datalen;
ssize_t rcode;
uint32_t vendor;
* will break assumptions about CUI. We know
* this, but Coverity doesn't.
*/
- if (da->type != PW_TYPE_STRING) return -1;
+ if (da->type != PW_TYPE_OCTETS) return -1;
#endif
- data = (uint8_t const *) "";
- datalen = 1;
+ data = NULL;
+ datalen = 0;
goto alloc_cui; /* skip everything */
}
* Decrypt the attribute.
*/
if (secret && packet && (da->flags.encrypt != FLAG_ENCRYPT_NONE)) {
+ /*
+ * Encrypted attributes can only exist for the
+ * old-style format. Extended attributes CANNOT
+ * be encrypted.
+ */
+ if (attrlen > 253) {
+ return -1;
+ }
+
if (data == start) {
- if (attrlen < sizeof(buffer)) {
- memcpy(buffer, data, attrlen);
- } else {
- memcpy(buffer, data, sizeof(buffer));
- }
+ memcpy(buffer, data, attrlen);
}
data = buffer;
break;
case PW_TYPE_INTEGER:
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
case PW_TYPE_DATE:
case PW_TYPE_SIGNED:
if (datalen != 4) goto raw;
if (datalen != 8) goto raw;
break;
- case PW_TYPE_IPV6ADDR:
+ case PW_TYPE_IPV6_ADDR:
if (datalen != 16) goto raw;
break;
- case PW_TYPE_IPV6PREFIX:
+ case PW_TYPE_IPV6_PREFIX:
if ((datalen < 2) || (datalen > 18)) goto raw;
if (data[1] > 128) goto raw;
break;
if (datalen != 6) goto raw;
break;
- case PW_TYPE_COMBO_IP:
+ case PW_TYPE_IP_ADDR:
if (datalen == 4) {
child = dict_attrbytype(da->attr, da->vendor,
- PW_TYPE_IPADDR);
+ PW_TYPE_IPV4_ADDR);
} else if (datalen == 16) {
child = dict_attrbytype(da->attr, da->vendor,
- PW_TYPE_IPV6ADDR);
+ PW_TYPE_IPV6_ADDR);
} else {
goto raw;
}
da = child; /* re-write it */
break;
- case PW_TYPE_IPV4PREFIX:
+ case PW_TYPE_IPV4_PREFIX:
if (datalen != 6) goto raw;
if ((data[1] & 0x3f) > 32) goto raw;
break;
fr_strerror_printf("Internal sanity check %d", __LINE__);
return -1;
}
- tag = 0;
+ tag = TAG_NONE;
#ifndef NDEBUG
/*
* Fix for Coverity.
break;
case PW_TYPE_OCTETS:
- vp->vp_octets = talloc_memdup(vp, data, vp->length);
+ pairmemcpy(vp, data, vp->length);
break;
case PW_TYPE_ABINARY:
break;
case PW_TYPE_BYTE:
- vp->vp_integer = data[0];
+ vp->vp_byte = data[0];
break;
case PW_TYPE_SHORT:
- vp->vp_integer = (data[0] << 8) | data[1];
+ vp->vp_short = (data[0] << 8) | data[1];
break;
case PW_TYPE_INTEGER:
memcpy(&vp->vp_ether, data, 6);
break;
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
memcpy(&vp->vp_ipaddr, data, 4);
break;
memcpy(&vp->vp_ifid, data, 8);
break;
- case PW_TYPE_IPV6ADDR:
+ case PW_TYPE_IPV6_ADDR:
memcpy(&vp->vp_ipv6addr, data, 16);
break;
- case PW_TYPE_IPV6PREFIX:
+ case PW_TYPE_IPV6_PREFIX:
/*
* FIXME: double-check that
* (vp->vp_octets[1] >> 3) matches vp->length + 2
}
break;
- case PW_TYPE_IPV4PREFIX:
+ case PW_TYPE_IPV4_PREFIX:
/* FIXME: do the same double-check as for IPv6Prefix */
- memcpy(&vp->vp_ipv4prefix, buffer, sizeof(vp->vp_ipv4prefix));
+ memcpy(&vp->vp_ipv4prefix, data, vp->length);
/*
* /32 means "keep all bits". Otherwise, mask
memcpy(&addr, vp->vp_octets + 2, sizeof(addr));
mask = 1;
- mask <<= (32 - (buffer[1] & 0x3f));
+ mask <<= (32 - (data[1] & 0x3f));
mask--;
mask = ~mask;
mask = htonl(mask);
data, length, length, pvp);
}
-/**
- * @brief Converts vp_data to network byte order
+fr_thread_local_setup(uint8_t *, rad_vp2data_buff);
+
+/** Converts vp_data to network byte order
+ *
+ * Provide a pointer to a buffer which contains the value of the VALUE_PAIR
+ * in an architecture independent format.
+ *
+ * The pointer is only guaranteed to be valid between calls to rad_vp2data, and so long
+ * as the source VALUE_PAIR is not freed.
+ *
+ * @param out where to write the pointer to the value.
+ * @param vp to get the value from.
* @return -1 on error, or the length of the value
*/
-ssize_t rad_vp2data(VALUE_PAIR const *vp, uint8_t *out, size_t outlen)
+ssize_t rad_vp2data(uint8_t const **out, VALUE_PAIR const *vp)
{
- size_t len = 0;
+ uint8_t *buffer;
uint32_t lvalue;
uint64_t lvalue64;
- VERIFY_VP(vp);
+ *out = NULL;
- len = vp->length;
- if (outlen < len) {
- fr_strerror_printf("ERROR: rad_vp2data buffer passed too small");
- return -1;
+ buffer = fr_thread_local_init(rad_vp2data_buff, free);
+ if (!buffer) {
+ int ret;
+
+ buffer = malloc(sizeof(uint8_t) * sizeof(value_data_t));
+ if (!buffer) {
+ fr_strerror_printf("Failed allocating memory for rad_vp2data buffer");
+ return -1;
+ }
+
+ ret = fr_thread_local_set(rad_vp2data_buff, buffer);
+ if (ret != 0) {
+ fr_strerror_printf("Failed setting up TLS for rad_vp2data buffer: %s", strerror(errno));
+ free(buffer);
+ return -1;
+ }
}
+ VERIFY_VP(vp);
+
switch(vp->da->type) {
- case PW_TYPE_STRING:
- case PW_TYPE_OCTETS:
- case PW_TYPE_TLV:
- memcpy(out, vp->data.ptr, len);
- break;
+ case PW_TYPE_STRING:
+ case PW_TYPE_OCTETS:
+ case PW_TYPE_TLV:
+ memcpy(out, &vp->data.ptr, sizeof(*out));
+ break;
- /*
- * All of this data is at the same
- * location.
- */
- case PW_TYPE_IFID:
- case PW_TYPE_IPADDR:
- case PW_TYPE_IPV6ADDR:
- case PW_TYPE_IPV6PREFIX:
- case PW_TYPE_IPV4PREFIX:
- case PW_TYPE_ABINARY:
- memcpy(out, &vp->data, len);
- break;
+ /*
+ * All of these values are at the same location.
+ */
+ case PW_TYPE_IFID:
+ case PW_TYPE_IPV4_ADDR:
+ case PW_TYPE_IPV6_ADDR:
+ case PW_TYPE_IPV6_PREFIX:
+ case PW_TYPE_IPV4_PREFIX:
+ case PW_TYPE_ABINARY:
+ case PW_TYPE_ETHERNET:
+ case PW_TYPE_IP_ADDR:
+ case PW_TYPE_IP_PREFIX:
+ {
+ void const *p = &vp->data;
+ memcpy(out, &p, sizeof(*out));
+ break;
+ }
- case PW_TYPE_BYTE:
- out[0] = vp->vp_integer & 0xff;
- break;
+ case PW_TYPE_BOOLEAN:
+ buffer[0] = vp->vp_integer & 0x01;
+ *out = buffer;
+ break;
- case PW_TYPE_SHORT:
- out[0] = (vp->vp_integer >> 8) & 0xff;
- out[1] = vp->vp_integer & 0xff;
- break;
+ case PW_TYPE_BYTE:
+ buffer[0] = vp->vp_integer & 0xff;
+ *out = buffer;
+ break;
- case PW_TYPE_INTEGER:
- lvalue = htonl(vp->vp_integer);
- memcpy(out, &lvalue, sizeof(lvalue));
- break;
+ case PW_TYPE_SHORT:
+ buffer[0] = (vp->vp_integer >> 8) & 0xff;
+ buffer[1] = vp->vp_integer & 0xff;
+ *out = buffer;
+ break;
- case PW_TYPE_INTEGER64:
- lvalue64 = htonll(vp->vp_integer64);
- memcpy(out, &lvalue64, sizeof(lvalue64));
- break;
+ case PW_TYPE_INTEGER:
+ lvalue = htonl(vp->vp_integer);
+ memcpy(buffer, &lvalue, sizeof(lvalue));
+ *out = buffer;
+ break;
- case PW_TYPE_DATE:
- lvalue = htonl(vp->vp_date);
- memcpy(out, &lvalue, sizeof(lvalue));
- break;
+ case PW_TYPE_INTEGER64:
+ lvalue64 = htonll(vp->vp_integer64);
+ memcpy(buffer, &lvalue64, sizeof(lvalue64));
+ *out = buffer;
+ break;
- case PW_TYPE_SIGNED:
- {
- int32_t slvalue;
+ case PW_TYPE_DATE:
+ lvalue = htonl(vp->vp_date);
+ memcpy(buffer, &lvalue, sizeof(lvalue));
+ *out = buffer;
+ break;
- slvalue = htonl(vp->vp_signed);
- memcpy(out, &slvalue, sizeof(slvalue));
- break;
- }
- /* unknown type: ignore it */
- default:
- fr_strerror_printf("ERROR: Unknown attribute type %d",
- vp->da->type);
- return -1;
+ case PW_TYPE_SIGNED:
+ {
+ int32_t slvalue = htonl(vp->vp_signed);
+ memcpy(buffer, &slvalue, sizeof(slvalue));
+ *out = buffer;
+ break;
+ }
+
+ case PW_TYPE_INVALID:
+ case PW_TYPE_EXTENDED:
+ case PW_TYPE_LONG_EXTENDED:
+ case PW_TYPE_EVS:
+ case PW_TYPE_VSA:
+ case PW_TYPE_TIMEVAL:
+ case PW_TYPE_MAX:
+ fr_strerror_printf("Cannot get data for VALUE_PAIR type %i", vp->da->type);
+ return -1;
+
+ /* Don't add default */
}
- return len;
+ return vp->length;
}
/**
char const *secret)
{
int packet_length;
- int num_attributes;
+ uint32_t num_attributes;
uint8_t *ptr;
radius_packet_t *hdr;
VALUE_PAIR *head, **tail, *vp;
sizeof(fr_rand_pool.randrsl) - total);
if ((this < 0) && (errno != EINTR)) break;
if (this > 0) total += this;
- }
+ }
close(fd);
} else {
fr_rand_pool.randrsl[0] = fd;
reply->data = NULL;
reply->data_len = 0;
+#ifdef WITH_TCP
+ reply->proto = packet->proto;
+#endif
return reply;
}
if (!radius_packet_ptr || !*radius_packet_ptr) return;
radius_packet = *radius_packet_ptr;
+ VERIFY_PACKET(radius_packet);
+
pairfree(&radius_packet->vps);
talloc_free(radius_packet);
*radius_packet_ptr = NULL;
}
+
+/** Duplicate a RADIUS_PACKET
+ *
+ * @param ctx the context in which the packet is allocated. May be NULL if
+ * the packet is not associated with a REQUEST.
+ * @param in The packet to copy
+ * @return a new RADIUS_PACKET or NULL on error.
+ */
+RADIUS_PACKET *rad_copy_packet(TALLOC_CTX *ctx, RADIUS_PACKET const *in)
+{
+ RADIUS_PACKET *out;
+
+ out = rad_alloc(ctx, 0);
+ if (!out) return NULL;
+
+ /*
+ * Bootstrap by copying everything.
+ */
+ memcpy(out, in, sizeof(*out));
+
+ /*
+ * Then reset necessary fields
+ */
+ out->sockfd = -1;
+
+ out->data = NULL;
+ out->data_len = 0;
+
+ out->vps = paircopy(out, in->vps);
+ out->offset = 0;
+
+ return out;
+}
/*
- * rbtree.c Red-black balanced binary trees.
+ * rbtree.c RED-BLACK balanced binary trees.
*
* Version: $Id$
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
+ * 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.1 of the License, or
+ * (at your option) any later version.
*
- * This library is distributed in the hope that it will be useful,
+ * 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
- * Lesser General Public License for more details.
+ * 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 Lesser General Public
- * License along with this library; if not, write to the Free Software
+ * 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
*
* Copyright 2004,2006 The FreeRADIUS server project
#define PTHREAD_MUTEX_UNLOCK(_x)
#endif
-/* red-black tree description */
-typedef enum { Black, Red } NodeColor;
+/* Red-Black tree description */
+typedef enum {
+ BLACK,
+ RED
+} node_colour_t;
struct rbnode_t {
- rbnode_t *Left; /* left child */
- rbnode_t *Right; /* right child */
- rbnode_t *Parent; /* parent */
- NodeColor Color; /* node color (black, red) */
- void *Data; /* data stored in node */
+ rbnode_t *left; //!< Left child
+ rbnode_t *right; //!< Right child
+ rbnode_t *parent; //!< Parent
+ node_colour_t colour; //!< Node colour (BLACK, RED)
+ void *data; //!< data stored in node
};
-#define NIL &Sentinel /* all leafs are sentinels */
-static rbnode_t Sentinel = { NIL, NIL, NULL, Black, NULL};
+#define NIL &sentinel /* all leafs are sentinels */
+static rbnode_t sentinel = { NIL, NIL, NULL, BLACK, NULL};
struct rbtree_t {
#ifndef NDEBUG
- uint32_t magic;
+ uint32_t magic;
#endif
- rbnode_t *Root;
- int num_elements;
- int (*Compare)(void const *, void const *);
- int replace_flag;
- void (*freeNode)(void *);
+ rbnode_t *root;
+ int num_elements;
+ rb_comparator_t compare;
+ rb_free_t free;
+ bool replace;
#ifdef HAVE_PTHREAD_H
- int lock;
- pthread_mutex_t mutex;
+ bool lock;
+ pthread_mutex_t mutex;
#endif
};
#define RBTREE_MAGIC (0x5ad09c42)
-/*
- * Walks the tree to delete all nodes.
- * Does NOT re-balance it!
+/** Walks the tree to delete all nodes Does NOT re-balance it!
+ *
*/
-static void FreeWalker(rbtree_t *tree, rbnode_t *X)
+static void free_walker(rbtree_t *tree, rbnode_t *x)
{
- if (X->Left != NIL) FreeWalker(tree, X->Left);
- if (X->Right != NIL) FreeWalker(tree, X->Right);
+ (void) talloc_get_type_abort(x, rbnode_t);
- if (tree->freeNode) tree->freeNode(X->Data);
- free(X);
+ if (x->left != NIL) free_walker(tree, x->left);
+ if (x->right != NIL) free_walker(tree, x->right);
+
+ if (tree->free) tree->free(x->data);
+ talloc_free(x);
}
void rbtree_free(rbtree_t *tree)
PTHREAD_MUTEX_LOCK(tree);
/*
- * Walk the tree, deleting the nodes...
+ * walk the tree, deleting the nodes...
*/
- if (tree->Root != NIL) FreeWalker(tree, tree->Root);
+ if (tree->root != NIL) free_walker(tree, tree->root);
#ifndef NDEBUG
tree->magic = 0;
#endif
- tree->Root = NULL;
+ tree->root = NULL;
#ifdef HAVE_PTHREAD_H
if (tree->lock) pthread_mutex_destroy(&tree->mutex);
#endif
- free(tree);
+ talloc_free(tree);
}
-/*
- * Create a new red-black tree.
+/** Create a new RED-BLACK tree
+ *
*/
-rbtree_t *rbtree_create(int (*Compare)(void const *, void const *),
- void (*freeNode)(void *),
- int flags)
+rbtree_t *rbtree_create(rb_comparator_t compare, rb_free_t node_free, int flags)
{
- rbtree_t *tree;
+ rbtree_t *tree;
- if (!Compare) return NULL;
+ if (!compare) return NULL;
- tree = malloc(sizeof(*tree));
+ tree = talloc_zero(NULL, rbtree_t);
if (!tree) return NULL;
- memset(tree, 0, sizeof(*tree));
#ifndef NDEBUG
tree->magic = RBTREE_MAGIC;
#endif
- tree->Root = NIL;
- tree->Compare = Compare;
- tree->replace_flag = flags & RBTREE_FLAG_REPLACE;
+ tree->root = NIL;
+ tree->compare = compare;
+ tree->replace = (flags & RBTREE_FLAG_REPLACE) != 0 ? true : false;
#ifdef HAVE_PTHREAD_H
- tree->lock = flags & RBTREE_FLAG_LOCK;
+ tree->lock = (flags & RBTREE_FLAG_LOCK) != 0 ? true : false;
if (tree->lock) {
pthread_mutex_init(&tree->mutex, NULL);
}
#endif
- tree->freeNode = freeNode;
+ tree->free = node_free;
return tree;
}
-
-static void RotateLeft(rbtree_t *tree, rbnode_t *X)
+/** Rotate Node x to left
+ *
+ */
+static void rotate_left(rbtree_t *tree, rbnode_t *x)
{
- /**************************
- * rotate Node X to left *
- **************************/
-
- rbnode_t *Y = X->Right;
-
- /* establish X->Right link */
- X->Right = Y->Left;
- if (Y->Left != NIL) Y->Left->Parent = X;
-
- /* establish Y->Parent link */
- if (Y != NIL) Y->Parent = X->Parent;
- if (X->Parent) {
- if (X == X->Parent->Left)
- X->Parent->Left = Y;
- else
- X->Parent->Right = Y;
+
+ rbnode_t *y = x->right;
+
+ /* establish x->right link */
+ x->right = y->left;
+ if (y->left != NIL) y->left->parent = x;
+
+ /* establish y->parent link */
+ if (y != NIL) y->parent = x->parent;
+ if (x->parent) {
+ if (x == x->parent->left) {
+ x->parent->left = y;
+ } else {
+ x->parent->right = y;
+ }
} else {
- tree->Root = Y;
+ tree->root = y;
}
- /* link X and Y */
- Y->Left = X;
- if (X != NIL) X->Parent = Y;
+ /* link x and y */
+ y->left = x;
+ if (x != NIL) x->parent = y;
}
-static void RotateRight(rbtree_t *tree, rbnode_t *X)
+/** Rotate Node x to right
+ *
+ */
+static void rotate_right(rbtree_t *tree, rbnode_t *x)
{
- /****************************
- * rotate Node X to right *
- ****************************/
-
- rbnode_t *Y = X->Left;
-
- /* establish X->Left link */
- X->Left = Y->Right;
- if (Y->Right != NIL) Y->Right->Parent = X;
-
- /* establish Y->Parent link */
- if (Y != NIL) Y->Parent = X->Parent;
- if (X->Parent) {
- if (X == X->Parent->Right)
- X->Parent->Right = Y;
- else
- X->Parent->Left = Y;
+ rbnode_t *y = x->left;
+
+ /* establish x->left link */
+ x->left = y->right;
+ if (y->right != NIL) y->right->parent = x;
+
+ /* establish y->parent link */
+ if (y != NIL) y->parent = x->parent;
+ if (x->parent) {
+ if (x == x->parent->right) {
+ x->parent->right = y;
+ } else {
+ x->parent->left = y;
+ }
} else {
- tree->Root = Y;
+ tree->root = y;
}
- /* link X and Y */
- Y->Right = X;
- if (X != NIL) X->Parent = Y;
+ /* link x and y */
+ y->right = x;
+ if (x != NIL) x->parent = y;
}
-static void InsertFixup(rbtree_t *tree, rbnode_t *X)
+/** Maintain red-black tree balance after inserting node x
+ *
+ */
+static void insert_fixup(rbtree_t *tree, rbnode_t *x)
{
- /*************************************
- * maintain red-black tree balance *
- * after inserting node X *
- *************************************/
-
- /* check red-black properties */
- while (X != tree->Root && X->Parent->Color == Red) {
+ /* check RED-BLACK properties */
+ while ((x != tree->root) && (x->parent->colour == RED)) {
/* we have a violation */
- if (X->Parent == X->Parent->Parent->Left) {
- rbnode_t *Y = X->Parent->Parent->Right;
- if (Y->Color == Red) {
-
- /* uncle is red */
- X->Parent->Color = Black;
- Y->Color = Black;
- X->Parent->Parent->Color = Red;
- X = X->Parent->Parent;
+ if (x->parent == x->parent->parent->left) {
+ rbnode_t *y = x->parent->parent->right;
+ if (y->colour == RED) {
+
+ /* uncle is RED */
+ x->parent->colour = BLACK;
+ y->colour = BLACK;
+ x->parent->parent->colour = RED;
+ x = x->parent->parent;
} else {
- /* uncle is black */
- if (X == X->Parent->Right) {
- /* make X a left child */
- X = X->Parent;
- RotateLeft(tree, X);
+ /* uncle is BLACK */
+ if (x == x->parent->right) {
+ /* make x a left child */
+ x = x->parent;
+ rotate_left(tree, x);
}
- /* recolor and rotate */
- X->Parent->Color = Black;
- X->Parent->Parent->Color = Red;
- RotateRight(tree, X->Parent->Parent);
+ /* recolour and rotate */
+ x->parent->colour = BLACK;
+ x->parent->parent->colour = RED;
+ rotate_right(tree, x->parent->parent);
}
} else {
/* mirror image of above code */
- rbnode_t *Y = X->Parent->Parent->Left;
- if (Y->Color == Red) {
-
- /* uncle is red */
- X->Parent->Color = Black;
- Y->Color = Black;
- X->Parent->Parent->Color = Red;
- X = X->Parent->Parent;
+ rbnode_t *y = x->parent->parent->left;
+ if (y->colour == RED) {
+
+ /* uncle is RED */
+ x->parent->colour = BLACK;
+ y->colour = BLACK;
+ x->parent->parent->colour = RED;
+ x = x->parent->parent;
} else {
- /* uncle is black */
- if (X == X->Parent->Left) {
- X = X->Parent;
- RotateRight(tree, X);
+ /* uncle is BLACK */
+ if (x == x->parent->left) {
+ x = x->parent;
+ rotate_right(tree, x);
}
- X->Parent->Color = Black;
- X->Parent->Parent->Color = Red;
- RotateLeft(tree, X->Parent->Parent);
+ x->parent->colour = BLACK;
+ x->parent->parent->colour = RED;
+ rotate_left(tree, x->parent->parent);
}
}
}
- tree->Root->Color = Black;
+ tree->root->colour = BLACK;
}
-/*
- * Insert an element into the tree.
+/** Insert an element into the tree
+ *
*/
-rbnode_t *rbtree_insertnode(rbtree_t *tree, void *Data)
+rbnode_t *rbtree_insert_node(rbtree_t *tree, void *data)
{
- rbnode_t *Current, *Parent, *X;
-
- /***********************************************
- * allocate node for Data and insert in tree *
- ***********************************************/
+ rbnode_t *current, *parent, *x;
PTHREAD_MUTEX_LOCK(tree);
/* find where node belongs */
- Current = tree->Root;
- Parent = NULL;
- while (Current != NIL) {
+ current = tree->root;
+ parent = NULL;
+ while (current != NIL) {
int result;
/*
* See if two entries are identical.
*/
- result = tree->Compare(Data, Current->Data);
+ result = tree->compare(data, current->data);
if (result == 0) {
/*
* Don't replace the entry.
*/
- if (tree->replace_flag == 0) {
+ if (!tree->replace) {
PTHREAD_MUTEX_UNLOCK(tree);
return NULL;
}
/*
* Do replace the entry.
*/
- if (tree->freeNode) tree->freeNode(Current->Data);
- Current->Data = Data;
+ if (tree->free) tree->free(current->data);
+ current->data = data;
PTHREAD_MUTEX_UNLOCK(tree);
- return Current;
+ return current;
}
- Parent = Current;
- Current = (result < 0) ? Current->Left : Current->Right;
+ parent = current;
+ current = (result < 0) ? current->left : current->right;
}
/* setup new node */
- if ((X = malloc (sizeof(*X))) == NULL) {
+ x = talloc_zero(tree, rbnode_t);
+ if (!x) {
+ fr_strerror_printf("No memory for new rbtree node");
PTHREAD_MUTEX_UNLOCK(tree);
return NULL;
}
- X->Data = Data;
- X->Parent = Parent;
- X->Left = NIL;
- X->Right = NIL;
- X->Color = Red;
+ x->data = data;
+ x->parent = parent;
+ x->left = NIL;
+ x->right = NIL;
+ x->colour = RED;
/* insert node in tree */
- if (Parent) {
- if (tree->Compare(Data, Parent->Data) <= 0)
- Parent->Left = X;
- else
- Parent->Right = X;
+ if (parent) {
+ if (tree->compare(data, parent->data) <= 0) {
+ parent->left = x;
+ } else {
+ parent->right = x;
+ }
} else {
- tree->Root = X;
+ tree->root = x;
}
- InsertFixup(tree, X);
+ insert_fixup(tree, x);
tree->num_elements++;
PTHREAD_MUTEX_UNLOCK(tree);
- return X;
+ return x;
}
-bool rbtree_insert(rbtree_t *tree, void *Data)
+bool rbtree_insert(rbtree_t *tree, void *data)
{
- if (rbtree_insertnode(tree, Data)) return true;
+ if (rbtree_insert_node(tree, data)) return true;
return false;
}
-static void DeleteFixup(rbtree_t *tree, rbnode_t *X, rbnode_t *Parent)
+/** Maintain RED-BLACK tree balance after deleting node x
+ *
+ */
+static void delete_fixup(rbtree_t *tree, rbnode_t *x, rbnode_t *parent)
{
- /*************************************
- * maintain red-black tree balance *
- * after deleting node X *
- *************************************/
-
- while (X != tree->Root && X->Color == Black) {
- if (X == Parent->Left) {
- rbnode_t *W = Parent->Right;
- if (W->Color == Red) {
- W->Color = Black;
- Parent->Color = Red; /* Parent != NIL? */
- RotateLeft(tree, Parent);
- W = Parent->Right;
+
+ while (x != tree->root && x->colour == BLACK) {
+ if (x == parent->left) {
+ rbnode_t *w = parent->right;
+ if (w->colour == RED) {
+ w->colour = BLACK;
+ parent->colour = RED; /* parent != NIL? */
+ rotate_left(tree, parent);
+ w = parent->right;
}
- if (W->Left->Color == Black && W->Right->Color == Black) {
- if (W != NIL) W->Color = Red;
- X = Parent;
- Parent = X->Parent;
+ if ((w->left->colour == BLACK) && (w->right->colour == BLACK)) {
+ if (w != NIL) w->colour = RED;
+ x = parent;
+ parent = x->parent;
} else {
- if (W->Right->Color == Black) {
- if (W->Left != NIL) W->Left->Color = Black;
- W->Color = Red;
- RotateRight(tree, W);
- W = Parent->Right;
+ if (w->right->colour == BLACK) {
+ if (w->left != NIL) w->left->colour = BLACK;
+ w->colour = RED;
+ rotate_right(tree, w);
+ w = parent->right;
}
- W->Color = Parent->Color;
- if (Parent != NIL) Parent->Color = Black;
- if (W->Right->Color != Black) {
- W->Right->Color = Black;
+ w->colour = parent->colour;
+ if (parent != NIL) parent->colour = BLACK;
+ if (w->right->colour != BLACK) {
+ w->right->colour = BLACK;
}
- RotateLeft(tree, Parent);
- X = tree->Root;
+ rotate_left(tree, parent);
+ x = tree->root;
}
} else {
- rbnode_t *W = Parent->Left;
- if (W->Color == Red) {
- W->Color = Black;
- Parent->Color = Red; /* Parent != NIL? */
- RotateRight(tree, Parent);
- W = Parent->Left;
+ rbnode_t *w = parent->left;
+ if (w->colour == RED) {
+ w->colour = BLACK;
+ parent->colour = RED; /* parent != NIL? */
+ rotate_right(tree, parent);
+ w = parent->left;
}
- if (W->Right->Color == Black && W->Left->Color == Black) {
- if (W != NIL) W->Color = Red;
- X = Parent;
- Parent = X->Parent;
+ if ((w->right->colour == BLACK) && (w->left->colour == BLACK)) {
+ if (w != NIL) w->colour = RED;
+ x = parent;
+ parent = x->parent;
} else {
- if (W->Left->Color == Black) {
- if (W->Right != NIL) W->Right->Color = Black;
- W->Color = Red;
- RotateLeft(tree, W);
- W = Parent->Left;
+ if (w->left->colour == BLACK) {
+ if (w->right != NIL) w->right->colour = BLACK;
+ w->colour = RED;
+ rotate_left(tree, w);
+ w = parent->left;
}
- W->Color = Parent->Color;
- if (Parent != NIL) Parent->Color = Black;
- if (W->Left->Color != Black) {
- W->Left->Color = Black;
+ w->colour = parent->colour;
+ if (parent != NIL) parent->colour = BLACK;
+ if (w->left->colour != BLACK) {
+ w->left->colour = BLACK;
}
- RotateRight(tree, Parent);
- X = tree->Root;
+ rotate_right(tree, parent);
+ x = tree->root;
}
}
}
- if (X != NIL) X->Color = Black; /* Avoid cache-dirty on NIL */
+ if (x != NIL) x->colour = BLACK; /* Avoid cache-dirty on NIL */
}
-/*
- * Delete an element from the tree.
+/** Delete an element (z) from the tree
+ *
*/
-static void rbtree_delete_internal(rbtree_t *tree, rbnode_t *Z, int skiplock)
+static void rbtree_delete_internal(rbtree_t *tree, rbnode_t *z, bool skiplock)
{
- rbnode_t *X, *Y;
- rbnode_t *Parent;
-
- /*****************************
- * delete node Z from tree *
- *****************************/
+ rbnode_t *x, *y;
+ rbnode_t *parent;
- if (!Z || Z == NIL) return;
+ if (!z || z == NIL) return;
if (!skiplock) {
PTHREAD_MUTEX_LOCK(tree);
}
- if (Z->Left == NIL || Z->Right == NIL) {
- /* Y has a NIL node as a child */
- Y = Z;
+ if (z->left == NIL || z->right == NIL) {
+ /* y has a NIL node as a child */
+ y = z;
} else {
/* find tree successor with a NIL node as a child */
- Y = Z->Right;
- while (Y->Left != NIL) Y = Y->Left;
+ y = z->right;
+ while (y->left != NIL) y = y->left;
}
- /* X is Y's only child */
- if (Y->Left != NIL)
- X = Y->Left;
- else
- X = Y->Right; /* may be NIL! */
+ /* x is y's only child */
+ if (y->left != NIL) {
+ x = y->left;
+ } else {
+ x = y->right; /* may be NIL! */
+ }
- /* remove Y from the parent chain */
- Parent = Y->Parent;
- if (X != NIL) X->Parent = Parent;
+ /* remove y from the parent chain */
+ parent = y->parent;
+ if (x != NIL) x->parent = parent;
- if (Parent)
- if (Y == Parent->Left)
- Parent->Left = X;
- else
- Parent->Right = X;
- else
- tree->Root = X;
+ if (parent) {
+ if (y == parent->left) {
+ parent->left = x;
+ } else {
+ parent->right = x;
+ }
+ } else {
+ tree->root = x;
+ }
- if (Y != Z) {
- if (tree->freeNode) tree->freeNode(Z->Data);
- Z->Data = Y->Data;
- Y->Data = NULL;
+ if (y != z) {
+ if (tree->free) tree->free(z->data);
+ z->data = y->data;
+ y->data = NULL;
- if ((Y->Color == Black) && Parent)
- DeleteFixup(tree, X, Parent);
+ if ((y->colour == BLACK) && parent) {
+ delete_fixup(tree, x, parent);
+ }
/*
- * The user structure in Y->Data MAY include a
- * pointer to Y. In that case, we CANNOT delete
- * Y. Instead, we copy Z (which is now in the
- * tree) to Y, and fix up the parent/child
+ * The user structure in y->data MAy include a
+ * pointer to y. In that case, we CANNOT delete
+ * y. Instead, we copy z (which is now in the
+ * tree) to y, and fix up the parent/child
* pointers.
*/
- memcpy(Y, Z, sizeof(*Y));
+ memcpy(y, z, sizeof(*y));
- if (!Y->Parent) {
- tree->Root = Y;
+ if (!y->parent) {
+ tree->root = y;
} else {
- if (Y->Parent->Left == Z) Y->Parent->Left = Y;
- if (Y->Parent->Right == Z) Y->Parent->Right = Y;
+ if (y->parent->left == z) y->parent->left = y;
+ if (y->parent->right == z) y->parent->right = y;
}
- if (Y->Left->Parent == Z) Y->Left->Parent = Y;
- if (Y->Right->Parent == Z) Y->Right->Parent = Y;
+ if (y->left->parent == z) y->left->parent = y;
+ if (y->right->parent == z) y->right->parent = y;
- free(Z);
+ talloc_free(z);
} else {
- if (tree->freeNode) tree->freeNode(Y->Data);
+ if (tree->free) tree->free(y->data);
- if (Y->Color == Black)
- DeleteFixup(tree, X, Parent);
+ if (y->colour == BLACK)
+ delete_fixup(tree, x, parent);
- free(Y);
+ talloc_free(y);
}
tree->num_elements--;
PTHREAD_MUTEX_UNLOCK(tree);
}
}
-void rbtree_delete(rbtree_t *tree, rbnode_t *Z) {
- rbtree_delete_internal(tree, Z, 0);
+void rbtree_delete(rbtree_t *tree, rbnode_t *z) {
+ rbtree_delete_internal(tree, z, false);
}
-/*
- * Delete a node from the tree, based on given data, which MUST
- * have come from rbtree_finddata().
+/** Delete a node from the tree, based on given data, which MUST have come from rbtree_finddata().
+ *
+ *
*/
bool rbtree_deletebydata(rbtree_t *tree, void const *data)
{
}
-/*
- * Find an element in the tree, returning the data, not the node.
+/** Find an element in the tree, returning the data, not the node
+ *
*/
-rbnode_t *rbtree_find(rbtree_t *tree, void const *Data)
+rbnode_t *rbtree_find(rbtree_t *tree, void const *data)
{
- /*******************************
- * find node containing Data *
- *******************************/
-
- rbnode_t *Current;
-
+ rbnode_t *current;
PTHREAD_MUTEX_LOCK(tree);
- Current = tree->Root;
+ current = tree->root;
- while (Current != NIL) {
- int result = tree->Compare(Data, Current->Data);
+ while (current != NIL) {
+ int result = tree->compare(data, current->data);
if (result == 0) {
PTHREAD_MUTEX_UNLOCK(tree);
- return Current;
+ return current;
} else {
- Current = (result < 0) ?
- Current->Left : Current->Right;
+ current = (result < 0) ?
+ current->left : current->right;
}
}
return NULL;
}
-/*
- * Find the user data.
+/** Find the user data.
+ *
*/
-void *rbtree_finddata(rbtree_t *tree, void const *Data)
+void *rbtree_finddata(rbtree_t *tree, void const *data)
{
- rbnode_t *X;
+ rbnode_t *x;
- X = rbtree_find(tree, Data);
- if (!X) return NULL;
+ x = rbtree_find(tree, data);
+ if (!x) return NULL;
- return X->Data;
+ return x->data;
}
-/*
- * Find a node by data, perform a callback, and perhaps delete the node.
- */
-void *rbtree_callbydata(rbtree_t *tree, void const *Data,
- int (*callback)(void *, void *), void *context) {
-
- /*******************************
- * find node containing Data *
- *******************************/
-
- rbnode_t *Current;
-
-
- PTHREAD_MUTEX_LOCK(tree);
- Current = tree->Root;
-
- while (Current != NIL) {
- int result = tree->Compare(Data, Current->Data);
-
- if (result == 0) {
- void *data = Current->Data;
-
- if (callback(context, data) > 0) {
- rbtree_delete_internal(tree, Current, 1);
- if (tree->freeNode) {
- data = NULL;
- }
- }
- PTHREAD_MUTEX_UNLOCK(tree);
- return data;
- } else {
- Current = (result < 0) ?
- Current->Left : Current->Right;
- }
- }
-
- PTHREAD_MUTEX_UNLOCK(tree);
- return NULL;
-}
-
-/*
- * Walk the tree, Pre-order
+/** Walk the tree, Pre-order
*
- * We call ourselves recursively for each function, but that's OK,
- * as the stack is only log(N) deep, which is ~12 entries deep.
+ * We call ourselves recursively for each function, but that's OK,
+ * as the stack is only log(N) deep, which is ~12 entries deep.
*/
-static int WalkNodePreOrder(rbnode_t *X,
- int (*callback)(void *, void *), void *context)
+static int walk_node_pre_order(rbnode_t *x, rb_walker_t compare, void *context)
{
int rcode;
- rbnode_t *Left, *Right;
+ rbnode_t *left, *right;
- Left = X->Left;
- Right = X->Right;
+ left = x->left;
+ right = x->right;
- rcode = callback(context, X->Data);
+ rcode = compare(context, x->data);
if (rcode != 0) return rcode;
- if (Left != NIL) {
- rcode = WalkNodePreOrder(Left, callback, context);
+ if (left != NIL) {
+ rcode = walk_node_pre_order(left, compare, context);
if (rcode != 0) return rcode;
}
- if (Right != NIL) {
- rcode = WalkNodePreOrder(Right, callback, context);
+ if (right != NIL) {
+ rcode = walk_node_pre_order(right, compare, context);
if (rcode != 0) return rcode;
}
return 0; /* we know everything returned zero */
}
-/*
- * Inorder
+/** rbtree_in_order
+ *
*/
-static int WalkNodeInOrder(rbnode_t *X,
- int (*callback)(void *, void *), void *context)
+static int walk_node_in_order(rbnode_t *x, rb_walker_t compare, void *context)
{
int rcode;
- rbnode_t *Right;
+ rbnode_t *right;
- if (X->Left != NIL) {
- rcode = WalkNodeInOrder(X->Left, callback, context);
+ if (x->left != NIL) {
+ rcode = walk_node_in_order(x->left, compare, context);
if (rcode != 0) return rcode;
}
- Right = X->Right;
+ right = x->right;
- rcode = callback(context, X->Data);
+ rcode = compare(context, x->data);
if (rcode != 0) return rcode;
- if (Right != NIL) {
- rcode = WalkNodeInOrder(Right, callback, context);
+ if (right != NIL) {
+ rcode = walk_node_in_order(right, compare, context);
if (rcode != 0) return rcode;
}
}
-/*
- * PostOrder
+/** rbtree_post_order
+ *
*/
-static int WalkNodePostOrder(rbnode_t *X,
- int (*callback)(void *, void*), void *context)
+static int walk_node_post_order(rbnode_t *x, rb_walker_t compare, void *context)
{
int rcode;
- if (X->Left != NIL) {
- rcode = WalkNodePostOrder(X->Left, callback, context);
+ if (x->left != NIL) {
+ rcode = walk_node_post_order(x->left, compare, context);
if (rcode != 0) return rcode;
}
- if (X->Right != NIL) {
- rcode = WalkNodePostOrder(X->Right, callback, context);
+ if (x->right != NIL) {
+ rcode = walk_node_post_order(x->right, compare, context);
if (rcode != 0) return rcode;
}
- rcode = callback(context, X->Data);
+ rcode = compare(context, x->data);
if (rcode != 0) return rcode;
return 0; /* we know everything returned zero */
}
-/*
- * DeleteOrder
+/** rbtree_delete_order
*
- * This executes an InOrder-like walk that adapts to changes in the
- * tree above it, which may occur because we allow the callback to
+ * This executes an rbtree_in_order-like walk that adapts to changes in the
+ * tree above it, which may occur because we allow the compare to
* tell us to delete the current node.
+ *
+ * The compare should return:
+ *
+ * < 0 - on error
+ * 0 - continue walking, don't delete the node
+ * 1 - delete the node and stop walking
+ * 2 - delete the node and continue walking
*/
-static int WalkDeleteOrder(rbtree_t *tree, int (*callback)(void *, void *),
- void *context)
+static int walk_delete_order(rbtree_t *tree, rb_walker_t compare, void *context)
{
- rbnode_t *Solid, *X;
+ rbnode_t *solid, *x;
int rcode = 0;
/* Keep track of last node that refused deletion. */
- Solid = NIL;
- while (Solid == NIL) {
- X = tree->Root;
- if (X == NIL) break;
+ solid = NIL;
+ while (solid == NIL) {
+ x = tree->root;
+ if (x == NIL) break;
descend:
- while (X->Left != NIL) {
- X = X->Left;
+ while (x->left != NIL) {
+ x = x->left;
}
visit:
- rcode = callback(context, X->Data);
+ rcode = compare(context, x->data);
if (rcode < 0) {
return rcode;
}
if (rcode) {
- rbtree_delete_internal(tree, X, 1);
+ rbtree_delete_internal(tree, x, true);
if (rcode != 2) {
return rcode;
}
- }
- else {
- Solid = X;
+ } else {
+ solid = x;
}
}
- if (Solid != NIL) {
- X = Solid;
- if (X->Right != NIL) {
- X = X->Right;
+ if (solid != NIL) {
+ x = solid;
+ if (x->right != NIL) {
+ x = x->right;
goto descend;
}
- while (X->Parent) {
- if (X->Parent->Left == X) {
- X = X->Parent;
+ while (x->parent) {
+ if (x->parent->left == x) {
+ x = x->parent;
goto visit;
}
- X = X->Parent;
+ x = x->parent;
}
}
return rcode;
/*
- * Walk the entire tree. The callback function CANNOT modify
+ * walk the entire tree. The compare function CANNOT modify
* the tree.
*
- * The callback function should return 0 to continue walking.
+ * The compare function should return 0 to continue walking.
* Any other value stops the walk, and is returned.
*/
-int rbtree_walk(rbtree_t *tree, RBTREE_ORDER order,
- int (*callback)(void *, void *), void *context)
+int rbtree_walk(rbtree_t *tree, rb_order_t order, rb_walker_t compare, void *context)
{
int rcode;
- if (tree->Root == NIL) return 0;
+ if (tree->root == NIL) return 0;
PTHREAD_MUTEX_LOCK(tree);
+
switch (order) {
- case PreOrder:
- rcode = WalkNodePreOrder(tree->Root, callback, context);
+ case RBTREE_PRE_ORDER:
+ rcode = walk_node_pre_order(tree->root, compare, context);
break;
- case InOrder:
- rcode = WalkNodeInOrder(tree->Root, callback, context);
+
+ case RBTREE_IN_ORDER:
+ rcode = walk_node_in_order(tree->root, compare, context);
break;
- case PostOrder:
- rcode = WalkNodePostOrder(tree->Root, callback, context);
+
+ case RBTREE_POST_ORDER:
+ rcode = walk_node_post_order(tree->root, compare, context);
break;
- case DeleteOrder:
- rcode = WalkDeleteOrder(tree, callback, context);
+
+ case RBTREE_DELETE_ORDER:
+ rcode = walk_delete_order(tree, compare, context);
break;
+
default:
rcode = -1;
break;
return rcode;
}
-int rbtree_num_elements(rbtree_t *tree)
+uint32_t rbtree_num_elements(rbtree_t *tree)
{
if (!tree) return 0;
return tree->num_elements;
}
-
/*
* Given a Node, return the data.
*/
{
if (!node) return NULL;
- return node->Data;
-}
-
-/*
- * Return left-most child.
- */
-void *rbtree_min(rbtree_t *tree)
-{
- void *data;
- rbnode_t *Current;
-
- if (!tree || !tree->Root) return NULL;
-
- PTHREAD_MUTEX_LOCK(tree);
- Current = tree->Root;
- while (Current->Left != NIL) Current = Current->Left;
-
- data = Current->Data;
- PTHREAD_MUTEX_UNLOCK(tree);
- return data;
+ return node->data;
}
#include "../include/sha1.h"
#ifndef WITH_OPENSSL_SHA1
-#define blk0(i) (block->l[i] = htonl(block->l[i]))
+# define blk0(i) (block->l[i] = htonl(block->l[i]))
-#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+# define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
/* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */
-#define blk0(i) (block->l[i] = htonl(block->l[i]))
+# define blk0(i) (block->l[i] = htonl(block->l[i]))
-#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+# define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
^block->l[(i+2)&15]^block->l[i&15],1))
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
-#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
-#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
-#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
-#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
-#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+# define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+# define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+# define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+# define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+# define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
/* Hash a single 512-bit block. This is the core of the algorithm. */
void fr_SHA1Transform(uint32_t state[5], uint8_t const buffer[64])
{
- uint32_t a, b, c, d, e;
- typedef union {
- uint8_t c[64];
- uint32_t l[16];
- } CHAR64LONG16;
- CHAR64LONG16 *block;
- uint8_t workspace[64];
-
- block = (CHAR64LONG16*)workspace;
- memcpy(block, buffer, 64);
- /* Copy context->state[] to working vars */
- a = state[0];
- b = state[1];
- c = state[2];
- d = state[3];
- e = state[4];
- /* 4 rounds of 20 operations each. Loop unrolled. */
- R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
- R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
- R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
- R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
- R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
- R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
- R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
- R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
- R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
- R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
- R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
- R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
- R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
- R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
- R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
- R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
- R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
- R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
- R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
- R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
- /* Add the working vars back into context.state[] */
- state[0] += a;
- state[1] += b;
- state[2] += c;
- state[3] += d;
- state[4] += e;
-
-#ifndef __clang_analyzer__
- /* Wipe variables */
- a = b = c = d = e = 0;
-#endif
+ uint32_t a, b, c, d, e;
+ typedef union {
+ uint8_t c[64];
+ uint32_t l[16];
+ } CHAR64LONG16;
+ CHAR64LONG16 *block;
+ uint8_t workspace[64];
+
+ block = (CHAR64LONG16*)workspace;
+ memcpy(block, buffer, 64);
+
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+
+# ifndef __clang_analyzer__
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+# endif
}
void fr_SHA1Init(fr_SHA1_CTX* context)
{
- /* SHA1 initialization constants */
- context->state[0] = 0x67452301;
- context->state[1] = 0xEFCDAB89;
- context->state[2] = 0x98BADCFE;
- context->state[3] = 0x10325476;
- context->state[4] = 0xC3D2E1F0;
- context->count[0] = context->count[1] = 0;
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
}
-
/* Run your data through this. */
-
void fr_SHA1Update(fr_SHA1_CTX *context,uint8_t const *data, size_t len)
{
-unsigned int i, j;
+ unsigned int i, j;
- j = (context->count[0] >> 3) & 63;
- if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
- context->count[1] += (len >> 29);
- if ((j + len) > 63) {
- memcpy(&context->buffer[j], data, (i = 64-j));
- fr_SHA1Transform(context->state, context->buffer);
- for ( ; i + 63 < len; i += 64) {
- fr_SHA1Transform(context->state, &data[i]);
+ j = (context->count[0] >> 3) & 63;
+ if ((context->count[0] += len << 3) < (len << 3)) {
+ context->count[1]++;
+ }
+
+ context->count[1] += (len >> 29);
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64-j));
+ fr_SHA1Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ fr_SHA1Transform(context->state, &data[i]);
+ }
+ j = 0;
+ } else {
+ i = 0;
}
- j = 0;
- }
- else i = 0;
- memcpy(&context->buffer[j], &data[i], len - i);
+ memcpy(&context->buffer[j], &data[i], len - i);
}
void fr_SHA1Final(uint8_t digest[20], fr_SHA1_CTX* context)
{
-uint32_t i, j;
-uint8_t finalcount[8];
-
- for (i = 0; i < 8; i++) {
- finalcount[i] = (uint8_t)((context->count[(i >= 4 ? 0 : 1)]
- >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
- }
- fr_SHA1Update(context, (unsigned char const *) "\200", 1);
- while ((context->count[0] & 504) != 448) {
- fr_SHA1Update(context, (unsigned char const *) "\0", 1);
- }
- fr_SHA1Update(context, finalcount, 8); /* Should cause a fr_SHA1Transform() */
- for (i = 0; i < 20; i++) {
- digest[i] = (uint8_t)
- ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
- }
-
-#ifndef __clang_analyzer__
- /* Wipe variables */
- i = j = 0;
- memset(context->buffer, 0, 64);
- memset(context->state, 0, 20);
- memset(context->count, 0, 8);
- memset(&finalcount, 0, 8);
-#endif
+ uint32_t i, j;
+ uint8_t finalcount[8];
-#ifdef SHA1HANDSOFF /* make fr_SHA1Transform overwrite it's own static vars */
- fr_SHA1Transform(context->state, context->buffer);
-#endif
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (uint8_t)((context->count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+
+ fr_SHA1Update(context, (unsigned char const *) "\200", 1);
+
+ while ((context->count[0] & 504) != 448) {
+ fr_SHA1Update(context, (unsigned char const *) "\0", 1);
+ }
+ fr_SHA1Update(context, finalcount, 8); /* Should cause a fr_SHA1Transform() */
+ for (i = 0; i < 20; i++) {
+ digest[i] = (uint8_t)((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+
+# ifndef __clang_analyzer__
+ /* Wipe variables */
+ i = j = 0;
+ memset(context->buffer, 0, 64);
+ memset(context->state, 0, 20);
+ memset(context->count, 0, 8);
+ memset(&finalcount, 0, 8);
+# endif
+
+# ifdef SHA1HANDSOFF /* make fr_SHA1Transform overwrite it's own static vars */
+ fr_SHA1Transform(context->state, context->buffer);
+# endif
}
void fr_SHA1FinalNoLen(uint8_t digest[20], fr_SHA1_CTX* context)
{
- uint32_t i, j;
-
- for (i = 0; i < 20; i++) {
- digest[i] = (uint8_t)
- ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
- }
-
-#ifndef __clang_analyzer__
- /* Wipe variables */
- i = j = 0;
- memset(context->buffer, 0, 64);
- memset(context->state, 0, 20);
- memset(context->count, 0, 8);
-#endif
+ uint32_t i, j;
-#ifdef SHA1HANDSOFF /* make fr_SHA1Transform overwrite it's own static vars */
- fr_SHA1Transform(context->state, context->buffer);
-#endif
+ for (i = 0; i < 20; i++) {
+ digest[i] = (uint8_t)((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+
+# ifndef __clang_analyzer__
+ /* Wipe variables */
+ i = j = 0;
+ memset(context->buffer, 0, 64);
+ memset(context->state, 0, 20);
+ memset(context->count, 0, 8);
+# endif
+
+# ifdef SHA1HANDSOFF /* make fr_SHA1Transform overwrite it's own static vars */
+ fr_SHA1Transform(context->state, context->buffer);
+# endif
}
#endif
#define MAX_PACKET_LEN 4096
/*
- * Open a socket on the given IP and port.
- */
-int fr_tcp_socket(fr_ipaddr_t *ipaddr, int port)
-{
- int sockfd;
- int on = 1;
- struct sockaddr_storage salocal;
- socklen_t salen;
-
- if ((port < 0) || (port > 65535)) {
- fr_strerror_printf("Port %d is out of allowed bounds", port);
- return -1;
- }
-
- sockfd = socket(ipaddr->af, SOCK_STREAM, 0);
- if (sockfd < 0) {
- return sockfd;
- }
-
- if (fr_nonblock(sockfd) < 0) {
- close(sockfd);
- return -1;
- }
-
- if (!fr_ipaddr2sockaddr(ipaddr, port, &salocal, &salen)) {
- close(sockfd);
- return -1;
- }
-
-#ifdef HAVE_STRUCT_SOCKADDR_IN6
- if (ipaddr->af == AF_INET6) {
- /*
- * Listening on '::' does NOT get you IPv4 to
- * IPv6 mapping. You've got to listen on an IPv4
- * address, too. This makes the rest of the server
- * design a little simpler.
- */
-#ifdef IPV6_V6ONLY
-
- if (IN6_IS_ADDR_UNSPECIFIED(&ipaddr->ipaddr.ip6addr)) {
- if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
- (char *)&on, sizeof(on)) < 0) {
- fr_strerror_printf("Failed in setsockopt(): %s",
- strerror(errno));
- close(sockfd);
- return -1;
- }
- }
-#endif /* IPV6_V6ONLY */
- }
-#endif /* HAVE_STRUCT_SOCKADDR_IN6 */
-
- if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
- fr_strerror_printf("Failed in setsockopt(): %s", strerror(errno));
- close(sockfd);
- return -1;
- }
-
- if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
- fr_strerror_printf("Failed in bind(): %s", strerror(errno));
- close(sockfd);
- return -1;
- }
-
- if (listen(sockfd, 8) < 0) {
- fr_strerror_printf("Failed in listen(): %s", strerror(errno));
- close(sockfd);
- return -1;
- }
-
- return sockfd;
-}
-
-
-/*
* Open a socket TO the given IP and port.
*/
int fr_tcp_client_socket(fr_ipaddr_t *src_ipaddr,
- fr_ipaddr_t *dst_ipaddr, int dst_port)
+ fr_ipaddr_t *dst_ipaddr, uint16_t dst_port)
{
int sockfd;
struct sockaddr_storage salocal;
socklen_t salen;
- if ((dst_port < 0) || (dst_port > 65535)) {
- fr_strerror_printf("Port %d is out of allowed bounds",
- dst_port);
- return -1;
- }
-
if (!dst_ipaddr) return -1;
sockfd = socket(dst_ipaddr->af, SOCK_STREAM, 0);
return sockfd;
}
-#if 0
-#ifdef O_NONBLOCK
- {
- int flags;
-
- if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0) {
- fr_strerror_printf("Failure getting socket flags: %s",
- strerror(errno));
- close(sockfd);
- return -1;
- }
-
- flags |= O_NONBLOCK;
- if( fcntl(sockfd, F_SETFL, flags) < 0) {
- fr_strerror_printf("Failure setting socket flags: %s",
- strerror(errno));
- close(sockfd);
- return -1;
- }
- }
-#endif
-#endif
/*
* Allow the caller to bind us to a specific source IP.
*/
if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
fr_strerror_printf("Failure binding to IP: %s",
- strerror(errno));
+ fr_syserror(errno));
close(sockfd);
return -1;
}
}
if (!fr_ipaddr2sockaddr(dst_ipaddr, dst_port, &salocal, &salen)) {
- close(sockfd);
+ close(sockfd);
return -1;
}
* socket is ready...
*/
if (connect(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
- fr_strerror_printf("Failed in connect(): %s", strerror(errno));
+ fr_strerror_printf("Failed in connect(): %s", fr_syserror(errno));
close(sockfd);
return -1;
}
if (len < 0) {
fr_strerror_printf("Error receiving packet: %s",
- strerror(errno));
+ fr_syserror(errno));
return -1;
}
packet_len = (packet->vector[2] << 8) | packet->vector[3];
if (packet_len < AUTH_HDR_LEN) {
- fr_strerror_printf("Discarding packet: Smaller than RFC minimum of 20 bytes.");
+ fr_strerror_printf("Discarding packet: Smaller than RFC minimum of 20 bytes");
return -1;
}
* If the packet is too big, then the socket is bad.
*/
if (packet_len > MAX_PACKET_LEN) {
- fr_strerror_printf("Discarding packet: Larger than RFC limitation of 4096 bytes.");
+ fr_strerror_printf("Discarding packet: Larger than RFC limitation of 4096 bytes");
return -1;
}
#endif
if (len < 0) {
- fr_strerror_printf("Error receiving packet: %s", strerror(errno));
+ fr_strerror_printf("Error receiving packet: %s", fr_syserror(errno));
return -1;
}
/*
* See if it's a well-formed RADIUS packet.
*/
- if (!rad_packet_ok(packet, flags)) {
+ if (!rad_packet_ok(packet, flags, NULL)) {
return -1;
}
}
- if ((packet->code > 0) && (packet->code < FR_MAX_PACKET_CODE)) {
- DEBUG("rad_recv: %s packet from %s",
+ if (is_radius_code(packet->code)) {
+ DEBUG("Received %s packet from %s",
fr_packet_codes[packet->code], buffer);
} else {
- DEBUG("rad_recv: Packet from %s code=%d",
+ DEBUG("Received packet from %s code %d",
buffer, packet->code);
}
DEBUG(", id=%d, length=%zu\n", packet->id, packet->data_len);
return 1; /* done reading the packet */
}
-RADIUS_PACKET *fr_tcp_accept(int sockfd)
-{
- int newfd;
- socklen_t salen;
- RADIUS_PACKET *packet;
- struct sockaddr_storage src;
-
- salen = sizeof(src);
-
- newfd = accept(sockfd, (struct sockaddr *) &src, &salen);
- if (newfd < 0) {
- /*
- * Non-blocking sockets must handle this.
- */
-#ifdef EWOULDBLOCK
- if (errno == EWOULDBLOCK) {
- packet = rad_alloc(NULL, 0);
- if (!packet) return NULL;
-
- packet->sockfd = sockfd;
- packet->src_ipaddr.af = AF_UNSPEC;
- return packet;
- }
-#endif
-
- return NULL;
- }
-
- packet = rad_alloc(NULL, 0);
- if (!packet) {
- close(newfd);
- return NULL;
- }
-
- if (src.ss_family == AF_INET) {
- struct sockaddr_in s4;
-
- memcpy(&s4, &src, sizeof(s4));
- packet->src_ipaddr.af = AF_INET;
- packet->src_ipaddr.ipaddr.ip4addr = s4.sin_addr;
- packet->src_port = ntohs(s4.sin_port);
-
-#ifdef HAVE_STRUCT_SOCKADDR_IN6
- } else if (src.ss_family == AF_INET6) {
- struct sockaddr_in6 s6;
-
- memcpy(&s6, &src, sizeof(s6));
- packet->src_ipaddr.af = AF_INET6;
- packet->src_ipaddr.ipaddr.ip6addr = s6.sin6_addr;
- packet->src_port = ntohs(s6.sin6_port);
-
-#endif
- } else {
- rad_free(&packet);
- close(newfd);
- return NULL;
- }
-
- packet->sockfd = newfd;
-
- /*
- * Note: Caller has to set dst_ipaddr && dst_port.
- */
- return packet;
-}
-
-
-/*
- * Writes a packet, assuming it's already been encoded.
- *
- * It returns the number of bytes written, which MAY be less than
- * the packet size (data_len). It is the caller's responsibility
- * to check the return code, and to schedule writes again.
- */
-ssize_t fr_tcp_write_packet(RADIUS_PACKET *packet)
-{
- ssize_t rcode;
-
- if (!packet || !packet->data) return 0;
-
- if (packet->partial >= packet->data_len) return packet->data_len;
-
- rcode = write(packet->sockfd, packet->data + packet->partial,
- packet->data_len - packet->partial);
- if (rcode < 0) return packet->partial; /* ignore most errors */
-
- packet->partial += rcode;
-
- return packet->partial;
-}
#endif /* WITH_TCP */
* Returns 0 or special token value.
*/
static FR_TOKEN getthing(char const **ptr, char *buf, int buflen, int tok,
- FR_NAME_NUMBER const *tokenlist)
+ FR_NAME_NUMBER const *tokenlist, bool unescape)
{
char *s;
char const *p;
- int quote, end = 0;
+ char quote;
+ bool end = false;
unsigned int x;
FR_NAME_NUMBER const *t;
FR_TOKEN rcode;
- buf[0] = 0;
+ buf[0] = '\0';
/* Skip whitespace */
p = *ptr;
}
/* Read word. */
- quote = 0;
+ quote = '\0';
if ((*p == '"') ||
(*p == '\'') ||
(*p == '`')) {
quote = *p;
- end = 0;
+ end = false;
p++;
}
s = buf;
while (*p && buflen-- > 1) {
- if (quote && (*p == '\\')) {
+ if (unescape && quote && (*p == '\\')) {
p++;
switch(*p) {
continue;
}
if (quote && (*p == quote)) {
- end = 1;
+ end = true;
p++;
break;
}
* Read a "word" - this means we don't honor
* tokens as delimiters.
*/
-int getword(char const **ptr, char *buf, int buflen)
+int getword(char const **ptr, char *buf, int buflen, bool unescape)
{
- return getthing(ptr, buf, buflen, 0, fr_tokens) == T_EOL ? 0 : 1;
+ return getthing(ptr, buf, buflen, 0, fr_tokens, unescape) == T_EOL ? 0 : 1;
}
-/*
- * Read a bare "word" - this means we don't honor
- * tokens as delimiters.
- */
-int getbareword(char const **ptr, char *buf, int buflen)
-{
- FR_TOKEN token;
-
- token = getthing(ptr, buf, buflen, 0, NULL);
- if (token != T_BARE_WORD) {
- return 0;
- }
-
- return 1;
-}
/*
* Read the next word, use tokens as delimiters.
*/
-FR_TOKEN gettoken(char const **ptr, char *buf, int buflen)
+FR_TOKEN gettoken(char const **ptr, char *buf, int buflen, bool unescape)
{
- return getthing(ptr, buf, buflen, 1, fr_tokens);
+ return getthing(ptr, buf, buflen, 1, fr_tokens, unescape);
}
/*
* Expect a string.
*/
-FR_TOKEN getstring(char const **ptr, char *buf, int buflen)
+FR_TOKEN getstring(char const **ptr, char *buf, int buflen, bool unescape)
{
char const *p;
*ptr = p;
if ((*p == '"') || (*p == '\'') || (*p == '`')) {
- return gettoken(ptr, buf, buflen);
+ return gettoken(ptr, buf, buflen, unescape);
}
- return getthing(ptr, buf, buflen, 0, fr_tokens);
+ return getthing(ptr, buf, buflen, 0, fr_tokens, unescape);
}
/*
/* Fallback to to using recvfrom */
# else
# undef IPV6_RECVPKTINFO
+# undef IPV6_PKTINFO
# endif
# else
# define FR_IPV6_RECVPKTINFO IPV6_PKTINFO
errno = ENOSYS;
- proto = -1;
+ /*
+ * Clang analyzer doesn't see that getsockname initialises
+ * the memory passed to it.
+ */
+#ifdef __clang_analyzer__
+ memset(&si, 0, sizeof(si));
+#endif
if (getsockname(s, (struct sockaddr *) &si, &si_len) < 0) {
return -1;
*/
proto = SOL_IP;
flag = IP_PKTINFO;
-#endif
-
+#else
#ifdef IP_RECVDSTADDR
+
/*
* Set the IP_RECVDSTADDR option (BSD). Note:
* IP_RECVDSTADDR == IP_SENDSRCADDR
*/
proto = IPPROTO_IP;
flag = IP_RECVDSTADDR;
+#else
+ return -1;
+#endif
#endif
#ifdef AF_INET6
* Work around Linux-specific hackery.
*/
flag = FR_IPV6_RECVPKTINFO;
+#else
+ return -1;
# endif
#endif
} else {
if (!to || !tolen) return recvfrom(s, buf, len, flags, from, fromlen);
/*
+ * Clang analyzer doesn't see that getsockname initialises
+ * the memory passed to it.
+ */
+#ifdef __clang_analyzer__
+ memset(&si, 0, sizeof(si));
+#endif
+
+ /*
* recvmsg doesn't provide sin_port so we have to
* retrieve it using getsockname().
*/
}
/* Set up iov and msgh structures. */
+ memset(&cbuf, 0, sizeof(cbuf));
memset(&msgh, 0, sizeof(struct msghdr));
iov.iov_base = buf;
iov.iov_len = len;
struct iovec iov;
char cbuf[256];
-#if !defined(IP_PKTINFO) && !defined(IP_SENDSRCADDR) && !defined(IPV6_PKTINFO)
+#ifdef __FreeBSD__
+ /*
+ * FreeBSD is extra pedantic about the use of IP_SENDSRCADDR,
+ * and sendmsg will fail with EINVAL if IP_SENDSRCADDR is used
+ * with a socket which is bound to something other than
+ * INADDR_ANY
+ */
+ struct sockaddr bound;
+ socklen_t bound_len = sizeof(bound);
+
+ if (getsockname(s, &bound, &bound_len) < 0) {
+ return -1;
+ }
+
+ switch (bound.sa_family) {
+ case AF_INET:
+ if (((struct sockaddr_in *) &bound)->sin_addr.s_addr != INADDR_ANY) {
+ from = NULL;
+ }
+ break;
+
+ case AF_INET6:
+ if (!IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) &bound)->sin6_addr))) {
+ from = NULL;
+ }
+ break;
+ }
+#else
+# if !defined(IP_PKTINFO) && !defined(IP_SENDSRCADDR) && !defined(IPV6_PKTINFO)
/*
* If the sendmsg() flags aren't defined, fall back to
* using sendto().
*/
from = NULL;
+# endif
#endif
/*
return sendto(s, buf, len, flags, to, tolen);
}
- /* Set up iov and msgh structures. */
+ /* Set up control buffer iov and msgh structures. */
+ memset(&cbuf, 0, sizeof(cbuf));
memset(&msgh, 0, sizeof(msgh));
memset(&iov, 0, sizeof(iov));
iov.iov_base = buf;
struct sockaddr_in from, to, in;
char buf[TESTLEN];
char *destip = DESTIP;
- int port = DEF_PORT;
+ uint16_t port = DEF_PORT;
int n, server_socket, client_socket, fl, tl, pid;
if (argc > 1) destip = argv[1];
}
#ifndef NDEBUG
- vp->vp_integer = FREE_MAGIC;
+ vp->vp_integer = 0xf4eef4ee;
#endif
#ifdef TALLOC_DEBUG
/*
* Caller must specify a da else we don't know what the attribute type is.
*/
- if (!da) return NULL;
+ if (!da) {
+ fr_strerror_printf("Invalid arguments");
+ return NULL;
+ }
vp = talloc_zero(ctx, VALUE_PAIR);
if (!vp) {
vp->da = da;
vp->op = T_OP_EQ;
+ vp->tag = TAG_ANY;
vp->type = VT_NONE;
+ vp->length = da->flags.length;
+
talloc_set_destructor(vp, _pairfree);
return vp;
VALUE_PAIR *vp;
vp_cursor_t cursor;
- if (!vps) {
+ if (!vps || !*vps) {
return;
}
- for (vp = paircursor(&cursor, vps);
+ for (vp = fr_cursor_init(&cursor, vps);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
VERIFY_VP(vp);
talloc_free(vp);
}
return 0;
}
-/** Find the pair with the matching attribute
+/** Find the pair with the matching DAs
*
- * @todo should take DAs and do a pointer comparison.
*/
-VALUE_PAIR *pairfind(VALUE_PAIR *vp, unsigned int attr, unsigned int vendor,
- int8_t tag)
+VALUE_PAIR *pairfind_da(VALUE_PAIR *vp, DICT_ATTR const *da, int8_t tag)
{
vp_cursor_t cursor;
VALUE_PAIR *i;
- for (i = paircursor(&cursor, &vp);
+ if(!fr_assert(da)) {
+ return NULL;
+ }
+
+ for (i = fr_cursor_init(&cursor, &vp);
i;
- i = pairnext(&cursor)) {
+ i = fr_cursor_next(&cursor)) {
VERIFY_VP(i);
- if ((i->da->attr == attr) && (i->da->vendor == vendor)
- && ((tag == TAG_ANY) || (i->da->flags.has_tag &&
- (i->tag == tag)))) {
+ if ((i->da == da) && (!i->da->flags.has_tag || TAG_EQ(tag, i->tag))) {
return i;
}
}
return NULL;
}
-/** Setup a cursor to iterate over attribute pairs
- *
- * @param cursor Where to initialise the cursor (uses existing structure).
- * @param node to start from.
- */
-VALUE_PAIR *paircursorc(vp_cursor_t *cursor, VALUE_PAIR const * const *node)
-{
- memset(cursor, 0, sizeof(*cursor));
-
- if (!node || !cursor) {
- return NULL;
- }
-
- memcpy(&cursor->first, &node, sizeof(cursor->first));
- cursor->current = *cursor->first;
-
- if (cursor->current) {
- VERIFY_VP(cursor->current);
- cursor->next = cursor->current->next;
- }
-
- return cursor->current;
-}
-
-VALUE_PAIR *pairfirst(vp_cursor_t *cursor)
-{
- cursor->current = *cursor->first;
-
- if (cursor->current) {
- VERIFY_VP(cursor->current);
- cursor->next = cursor->current->next;
- if (cursor->next) VERIFY_VP(cursor->next);
- cursor->found = NULL;
- }
-
- return cursor->current;
-}
-
-/** Iterate over attributes of a given type in the pairlist
- *
- *
- */
-VALUE_PAIR *pairfindnext(vp_cursor_t *cursor, unsigned int attr, unsigned int vendor, int8_t tag)
-{
- VALUE_PAIR *i;
-
- i = pairfind(!cursor->found ? cursor->current : cursor->found->next, attr, vendor, tag);
- if (!i) {
- cursor->next = NULL;
- cursor->current = NULL;
-
- return NULL;
- }
-
- cursor->next = i->next;
- cursor->current = i;
- cursor->found = i;
-
- return i;
-}
-
-/** Retrieve the next VALUE_PAIR
- *
- *
- */
-VALUE_PAIR *pairnext(vp_cursor_t *cursor)
-{
- cursor->current = cursor->next;
- if (cursor->current) {
- VERIFY_VP(cursor->current);
-
- /*
- * Set this now in case 'current' gets freed before
- * pairnext is called again.
- */
- cursor->next = cursor->current->next;
-
- /*
- * Next call to pairfindnext will start from the current
- * position in the list, not the last found instance.
- */
- cursor->found = NULL;
- }
-
- return cursor->current;
-}
-
-VALUE_PAIR *paircurrent(vp_cursor_t *cursor)
-{
- if (cursor->current) {
- VERIFY_VP(cursor->current);
- }
-
- return cursor->current;
-}
-/** Insert a VP
+/** Find the pair with the matching attribute
*
- * @todo don't use with pairdelete
+ * @todo should take DAs and do a pointer comparison.
*/
-void pairinsert(vp_cursor_t *cursor, VALUE_PAIR *add)
+VALUE_PAIR *pairfind(VALUE_PAIR *vp, unsigned int attr, unsigned int vendor, int8_t tag)
{
- VALUE_PAIR *i;
-
- if (!add) {
- return;
- }
-
- VERIFY_VP(add);
-
- /*
- * Cursor was initialised with a pointer to a NULL value_pair
- */
- if (!*cursor->first) {
- *cursor->first = add;
- cursor->current = add;
- cursor->next = cursor->current->next;
-
- return;
- }
-
- /*
- * We don't yet know where the last VALUE_PAIR is
- *
- * Assume current is closer to the end of the list and use that if available.
- */
- if (!cursor->last) {
- cursor->last = cursor->current ? cursor->current : *cursor->first;
- }
+ vp_cursor_t cursor;
+ VALUE_PAIR *i;
- VERIFY_VP(cursor->last);
+ VERIFY_LIST(vp);
- /*
- * Something outside of the cursor added another VALUE_PAIR
- */
- if (cursor->last->next) {
- for (i = cursor->last; i; i = i->next) {
- VERIFY_VP(i);
- cursor->last = i;
+ for (i = fr_cursor_init(&cursor, &vp);
+ i;
+ i = fr_cursor_next(&cursor)) {
+ if ((i->da->attr == attr) && (i->da->vendor == vendor) && \
+ (!i->da->flags.has_tag || TAG_EQ(tag, i->tag))) {
+ return i;
}
}
- /*
- * Either current was never set, or something iterated to the end of the
- * attribute list.
- */
- if (!cursor->current) {
- cursor->current = add;
- }
-
- cursor->last->next = add;
-}
-
-/** Remove the current pair
- *
- * @todo this is really inefficient and should be fixed...
- *
- * @param cursor to remove the current pair from.
- * @return NULL on error, else the VALUE_PAIR we just removed.
- */
-VALUE_PAIR *pairremove(vp_cursor_t *cursor)
-{
- VALUE_PAIR *vp, **last;
-
- vp = paircurrent(cursor);
- if (!vp) {
- return NULL;
- }
-
- last = cursor->first;
- while (*last != vp) {
- last = &(*last)->next;
- }
-
- pairnext(cursor); /* Advance the cursor past the one were about to delete */
-
- *last = vp->next;
- vp->next = NULL;
-
- return vp;
+ return NULL;
}
/** Delete matching pairs
* @param[in,out] first VP in list.
* @param[in] attr to match.
* @param[in] vendor to match.
- * @param[in] tag to match. TAG_ANY matches any tag, TAG_UNUSED matches tagless VPs.
+ * @param[in] tag to match. TAG_ANY matches any tag, TAG_NONE matches tagless VPs.
*
* @todo should take DAs and do a point comparison.
*/
VERIFY_VP(i);
next = i->next;
if ((i->da->attr == attr) && (i->da->vendor == vendor) &&
- ((tag == TAG_ANY) ||
- (i->da->flags.has_tag && (i->tag == tag)))) {
+ (!i->da->flags.has_tag || TAG_EQ(tag, i->tag))) {
*last = next;
talloc_free(i);
} else {
* Found the first attribute, replace it,
* and return.
*/
- if ((i->da == replace->da) &&
- (!i->da->flags.has_tag || (i->tag == replace->tag))
- ) {
+ if ((i->da == replace->da) && (!i->da->flags.has_tag || TAG_EQ(replace->tag, i->tag))) {
*prev = replace;
/*
*prev = replace;
}
+int8_t attrtagcmp(void const *a, void const *b)
+{
+ VALUE_PAIR const *my_a = a;
+ VALUE_PAIR const *my_b = b;
+
+ VERIFY_VP(my_a);
+ VERIFY_VP(my_b);
+
+ uint8_t cmp;
+
+ cmp = fr_pointer_cmp(my_a->da, my_b->da);
+
+ if (cmp != 0) return cmp;
+
+ if (my_a->tag < my_b->tag) {
+ return -1;
+ }
+
+ if (my_a->tag > my_b->tag) {
+ return 1;
+ }
+
+ return 0;
+}
+
static void pairsort_split(VALUE_PAIR *source, VALUE_PAIR **front, VALUE_PAIR **back)
{
VALUE_PAIR *fast;
* Stopping condition - no more elements left to split
*/
if (!source || !source->next) {
- *front = source;
- *back = NULL;
+ *front = source;
+ *back = NULL;
- return;
- }
+ return;
+ }
/*
* Fast advances twice as fast as slow, so when it gets to the end,
slow->next = NULL;
}
-static VALUE_PAIR *pairsort_merge(VALUE_PAIR *a, VALUE_PAIR *b, bool with_tag)
+static VALUE_PAIR *pairsort_merge(VALUE_PAIR *a, VALUE_PAIR *b, fr_cmp_t cmp)
{
VALUE_PAIR *result = NULL;
if (!a) return b;
if (!b) return a;
- /*
- * Compare the DICT_ATTRs and tags
- */
- if ((with_tag && (a->tag < b->tag)) || (a->da <= b->da)) {
+ /*
+ * Compare the DICT_ATTRs and tags
+ */
+ if (cmp(a, b) <= 0) {
result = a;
- result->next = pairsort_merge(a->next, b, with_tag);
- } else {
+ result->next = pairsort_merge(a->next, b, cmp);
+ } else {
result = b;
- result->next = pairsort_merge(a, b->next, with_tag);
+ result->next = pairsort_merge(a, b->next, cmp);
}
return result;
/** Sort a linked list of VALUE_PAIRs using merge sort
*
* @param[in,out] vps List of VALUE_PAIRs to sort.
- * @param[in] with_tag sort by tag then by DICT_ATTR
+ * @param[in] cmp to sort with
*/
-void pairsort(VALUE_PAIR **vps, bool with_tag)
+void pairsort(VALUE_PAIR **vps, fr_cmp_t cmp)
{
VALUE_PAIR *head = *vps;
VALUE_PAIR *a;
}
pairsort_split(head, &a, &b); /* Split into sublists */
- pairsort(&a, with_tag); /* Traverse left */
- pairsort(&b, with_tag); /* Traverse right */
+ pairsort(&a, cmp); /* Traverse left */
+ pairsort(&b, cmp); /* Traverse right */
+
+ /*
+ * merge the two sorted lists together
+ */
+ *vps = pairsort_merge(a, b, cmp);
+}
- /*
- * merge the two sorted lists together
- */
- *vps = pairsort_merge(a, b, with_tag);
+/** Write an error to the library errorbuff detailing the mismatch
+ *
+ * Retrieve output with fr_strerror();
+ *
+ * @todo add thread specific talloc contexts.
+ *
+ * @param ctx a hack until we have thread specific talloc contexts.
+ * @param failed pair of attributes which didn't match.
+ */
+void pairvalidate_debug(TALLOC_CTX *ctx, VALUE_PAIR const *failed[2])
+{
+ VALUE_PAIR const *filter = failed[0];
+ VALUE_PAIR const *list = failed[1];
+
+ char *value, *pair;
+
+ (void) fr_strerror(); /* Clear any existing messages */
+
+ if (!fr_assert(!(!filter && !list))) return;
+
+ if (!list) {
+ if (!filter) return;
+ fr_strerror_printf("Attribute \"%s\" not found in list", filter->da->name);
+ return;
+ }
+
+ if (!filter || (filter->da != list->da)) {
+ fr_strerror_printf("Attribute \"%s\" not found in filter", list->da->name);
+ return;
+ }
+
+ if (TAG_EQ(filter->tag, list->tag)) {
+ fr_strerror_printf("Attribute \"%s\" tag \"%i\" didn't match filter tag \"%i\"",
+ list->da->name, list->tag, filter->tag);
+ return;
+ }
+
+ pair = vp_aprint(ctx, filter);
+ value = vp_aprint_value(ctx, list);
+
+ fr_strerror_printf("Attribute value \"%s\" didn't match filter \"%s\"", value, pair);
+
+ talloc_free(pair);
+ talloc_free(value);
+
+ return;
}
/** Uses paircmp to verify all VALUE_PAIRs in list match the filter defined by check
*
+ * @note will sort both filter and list in place.
+ *
+ * @param failed pointer to an array to write the pointers of the filter/list attributes that didn't match.
+ * May be NULL.
* @param filter attributes to check list against.
* @param list attributes, probably a request or reply
*/
-bool pairvalidate(VALUE_PAIR *filter, VALUE_PAIR *list)
+bool pairvalidate(VALUE_PAIR const *failed[2], VALUE_PAIR *filter, VALUE_PAIR *list)
{
vp_cursor_t filter_cursor;
vp_cursor_t list_cursor;
if (!filter && !list) {
return true;
}
- if (!filter || !list) {
- return false;
- }
/*
* This allows us to verify the sets of validate and reply are equal
*
* @todo this should be removed one we have sets and lists
*/
- pairsort(&filter, true);
- pairsort(&list, true);
+ pairsort(&filter, attrtagcmp);
+ pairsort(&list, attrtagcmp);
- match = paircursor(&list_cursor, &list);
- check = paircursor(&filter_cursor, &filter);
+ check = fr_cursor_init(&filter_cursor, &filter);
+ match = fr_cursor_init(&list_cursor, &list);
while (true) {
+ if (!match && !check) goto mismatch;
+
/*
* The lists are sorted, so if the first
* attributes aren't of the same type, then we're
* done.
*/
- if (!attribute_eq(check, match)) {
- return false;
- }
+ if (!attribute_eq(check, match)) goto mismatch;
/*
* They're of the same type, but don't have the
* Note that the RFCs say that for attributes of
* the same type, order is important.
*/
- if (!paircmp(check, match)) {
- return false;
- }
-
- match = pairnext(&list_cursor);
- check = pairnext(&filter_cursor);
+ if (!paircmp(check, match)) goto mismatch;
- if (!match && !check) break;
+ check = fr_cursor_next(&filter_cursor);
+ match = fr_cursor_next(&list_cursor);
/*
* One list ended earlier than the others, they
* didn't match.
*/
- if (!match || !check) {
- return false;
+ if (!match || !check) break;
+ }
+
+ return true;
+
+mismatch:
+ if (failed) {
+ failed[0] = check;
+ failed[1] = match;
+ }
+ return false;
+}
+
+/** Uses paircmp to verify all VALUE_PAIRs in list match the filter defined by check
+ *
+ * @note will sort both filter and list in place.
+ *
+ * @param failed pointer to an array to write the pointers of the filter/list attributes that didn't match.
+ * May be NULL.
+ * @param filter attributes to check list against.
+ * @param list attributes, probably a request or reply
+ */
+bool pairvalidate_relaxed(VALUE_PAIR const *failed[2], VALUE_PAIR *filter, VALUE_PAIR *list)
+{
+ vp_cursor_t filter_cursor;
+ vp_cursor_t list_cursor;
+
+ VALUE_PAIR *check, *last_check = NULL, *match = NULL;
+
+ if (!filter && !list) {
+ return true;
+ }
+
+ /*
+ * This allows us to verify the sets of validate and reply are equal
+ * i.e. we have a validate rule which matches every reply attribute.
+ *
+ * @todo this should be removed one we have sets and lists
+ */
+ pairsort(&filter, attrtagcmp);
+ pairsort(&list, attrtagcmp);
+
+ fr_cursor_init(&list_cursor, &list);
+ for (check = fr_cursor_init(&filter_cursor, &filter);
+ check;
+ check = fr_cursor_next(&filter_cursor)) {
+ /*
+ * Were processing check attributes of a new type.
+ */
+ if (!attribute_eq(last_check, check)) {
+ /*
+ * Record the start of the matching attributes in the pair list
+ * For every other operator we require the match to be present
+ */
+ match = fr_cursor_next_by_da(&list_cursor, check->da, check->tag);
+ if (!match) {
+ if (check->op == T_OP_CMP_FALSE) continue;
+ goto mismatch;
+ }
+
+ fr_cursor_init(&list_cursor, &match);
+ last_check = check;
+ }
+
+ /*
+ * Now iterate over all attributes of the same type.
+ */
+ for (match = fr_cursor_first(&list_cursor);
+ attribute_eq(match, check);
+ match = fr_cursor_next(&list_cursor)) {
+ /*
+ * This attribute passed the filter
+ */
+ if (!paircmp(check, match)) goto mismatch;
}
}
return true;
+
+mismatch:
+ if (failed) {
+ failed[0] = check;
+ failed[1] = match;
+ }
+ return false;
}
/** Copy a single valuepair
VERIFY_VP(vp);
n = pairalloc(ctx, vp->da);
- if (!n) {
- fr_strerror_printf("out of memory");
- return NULL;
- }
+ if (!n) return NULL;
memcpy(n, vp, sizeof(*n));
* Now copy the value
*/
if (vp->type == VT_XLAT) {
- n->value.xlat = talloc_strdup(n, n->value.xlat);
+ n->value.xlat = talloc_typed_strdup(n, n->value.xlat);
}
n->da = dict_attr_copy(vp->da, true);
n->next = NULL;
- if ((n->da->type == PW_TYPE_TLV) ||
- (n->da->type == PW_TYPE_OCTETS)) {
- if (n->vp_octets != NULL) {
- n->vp_octets = talloc_memdup(n, vp->vp_octets, n->length);
- }
+ switch (vp->da->type) {
+ case PW_TYPE_TLV:
+ case PW_TYPE_OCTETS:
+ n->vp_octets = NULL; /* else pairmemcpy will free vp's value */
+ pairmemcpy(n, vp->vp_octets, n->length);
+ break;
- } else if (n->da->type == PW_TYPE_STRING) {
- if (n->vp_strvalue != NULL) {
- /*
- * Equivalent to, and faster than strdup.
- */
- n->vp_strvalue = talloc_memdup(n, vp->vp_strvalue, n->length + 1);
- }
+ case PW_TYPE_STRING:
+ n->vp_strvalue = NULL; /* else pairstrnpy will free vp's value */
+ pairstrncpy(n, vp->vp_strvalue, n->length);
+ break;
+
+ default:
+ break;
}
return n;
return NULL; /* can't do it */
case PW_TYPE_INTEGER:
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
case PW_TYPE_DATE:
case PW_TYPE_IFID:
- case PW_TYPE_IPV6ADDR:
- case PW_TYPE_IPV6PREFIX:
+ case PW_TYPE_IPV6_ADDR:
+ case PW_TYPE_IPV6_PREFIX:
case PW_TYPE_BYTE:
case PW_TYPE_SHORT:
case PW_TYPE_ETHERNET:
case PW_TYPE_SIGNED:
case PW_TYPE_INTEGER64:
- case PW_TYPE_IPV4PREFIX:
+ case PW_TYPE_IPV4_PREFIX:
break;
}
}
n = pairalloc(ctx, da);
- if (!n) {
- return NULL;
- }
+ if (!n) return NULL;
memcpy(n, vp, sizeof(*n));
n->da = da;
if (n->type == VT_XLAT) {
- n->value.xlat = talloc_strdup(n, n->value.xlat);
+ n->value.xlat = talloc_typed_strdup(n, n->value.xlat);
}
- switch (n->da->type) {
- case PW_TYPE_TLV:
- case PW_TYPE_OCTETS:
- if (n->vp_octets != NULL) {
- n->vp_octets = talloc_memdup(n, vp->vp_octets, n->length);
- }
- break;
+ if (n->data.ptr) switch (n->da->type) {
+ case PW_TYPE_TLV:
+ case PW_TYPE_OCTETS:
+ n->vp_octets = talloc_memdup(n, vp->vp_octets, n->length);
+ talloc_set_type(n->vp_octets, uint8_t);
+ break;
- case PW_TYPE_STRING:
- if (n->vp_strvalue != NULL) {
- n->vp_strvalue = talloc_memdup(n, vp->vp_strvalue, n->length + 1); /* NULL byte */
- }
- break;
- default:
- return NULL;
+ case PW_TYPE_STRING:
+ n->vp_strvalue = talloc_memdup(n, vp->vp_strvalue, n->length + 1); /* NULL byte */
+ talloc_set_type(n->vp_strvalue, char);
+ break;
+
+ default:
+ break;
}
n->next = NULL;
}
-/** Copy matching pairs
+/** Copy a pairlist.
*
- * Copy pairs of a matching attribute number, vendor number and tag from the
- * the input list to a new list, and returns the head of this list.
+ * Copy all pairs from 'from' regardless of tag, attribute or vendor.
*
- * @param[in] ctx for talloc
+ * @param[in] ctx for new VALUE_PAIRs to be allocated in.
* @param[in] from whence to copy VALUE_PAIRs.
- * @param[in] attr to match, if 0 input list will not be filtered by attr.
- * @param[in] vendor to match.
- * @param[in] tag to match, TAG_ANY matches any tag, TAG_UNUSED matches tagless VPs.
* @return the head of the new VALUE_PAIR list or NULL on error.
*/
-VALUE_PAIR *paircopy2(TALLOC_CTX *ctx, VALUE_PAIR *from,
- unsigned int attr, unsigned int vendor, int8_t tag)
+VALUE_PAIR *paircopy(TALLOC_CTX *ctx, VALUE_PAIR *from)
{
vp_cursor_t src, dst;
VALUE_PAIR *out = NULL, *vp;
- paircursor(&dst, &out);
- for (vp = paircursor(&src, &from);
+ fr_cursor_init(&dst, &out);
+ for (vp = fr_cursor_init(&src, &from);
vp;
- vp = pairnext(&src)) {
- VERIFY_VP(vp);
-
- if ((attr > 0) && ((vp->da->attr != attr) || (vp->da->vendor != vendor))) {
- continue;
- }
-
- if ((tag != TAG_ANY) && vp->da->flags.has_tag && (vp->tag != tag)) {
- continue;
- }
-
+ vp = fr_cursor_next(&src)) {
+ VERIFY_VP(vp);
vp = paircopyvp(ctx, vp);
if (!vp) {
pairfree(&out);
return NULL;
}
- pairinsert(&dst, vp);
+ fr_cursor_insert(&dst, vp); /* paircopy sets next pointer to NULL */
}
return out;
}
-
-/** Copy a pairlist.
+/** Copy matching pairs
*
- * Copy all pairs from 'from' regardless of tag, attribute or vendor.
+ * Copy pairs of a matching attribute number, vendor number and tag from the
+ * the input list to a new list, and returns the head of this list.
*
- * @param[in] ctx for new VALUE_PAIRs to be allocated in.
+ * @param[in] ctx for talloc
* @param[in] from whence to copy VALUE_PAIRs.
+ * @param[in] attr to match, if 0 input list will not be filtered by attr.
+ * @param[in] vendor to match.
+ * @param[in] tag to match, TAG_ANY matches any tag, TAG_NONE matches tagless VPs.
* @return the head of the new VALUE_PAIR list or NULL on error.
*/
-VALUE_PAIR *paircopy(TALLOC_CTX *ctx, VALUE_PAIR *from)
+VALUE_PAIR *paircopy2(TALLOC_CTX *ctx, VALUE_PAIR *from,
+ unsigned int attr, unsigned int vendor, int8_t tag)
{
vp_cursor_t src, dst;
VALUE_PAIR *out = NULL, *vp;
- paircursor(&dst, &out);
- for (vp = paircursor(&src, &from);
+ fr_cursor_init(&dst, &out);
+ for (vp = fr_cursor_init(&src, &from);
vp;
- vp = pairnext(&src)) {
- VERIFY_VP(vp);
- vp = paircopyvp(ctx, vp);
- if (!vp) {
- pairfree(&out);
- return NULL;
- }
- pairinsert(&dst, vp); /* paircopy sets next pointer to NULL */
+ vp = fr_cursor_next(&src)) {
+ VERIFY_VP(vp);
+
+ if ((vp->da->attr != attr) || (vp->da->vendor != vendor)) {
+ continue;
+ }
+
+ if (vp->da->flags.has_tag && TAG_EQ(tag, vp->tag)) {
+ continue;
+ }
+
+ vp = paircopyvp(ctx, vp);
+ if (!vp) {
+ pairfree(&out);
+ return NULL;
+ }
+ fr_cursor_insert(&dst, vp);
}
return out;
}
+/** Steal all members of a VALUE_PAIR list
+ *
+ * @param[in] ctx to move VALUE_PAIRs into
+ * @param[in] from VALUE_PAIRs to move into the new context.
+ */
+VALUE_PAIR *pairsteal(TALLOC_CTX *ctx, VALUE_PAIR *from)
+{
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+
+ for (vp = fr_cursor_init(&cursor, &from);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ (void) talloc_steal(ctx, vp);
+ }
+
+ return from;
+}
+
/** Move pairs from source list to destination list respecting operator
*
* @note This function does some additional magic that's probably not needed
*/
void pairmove(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from)
{
- VALUE_PAIR **tailto, *i, *j, *next;
- VALUE_PAIR *tailfrom = NULL;
- VALUE_PAIR *found;
- int has_password = 0;
+ VALUE_PAIR *i, *found;
+ VALUE_PAIR *head_new, **tail_new;
+ VALUE_PAIR **tail_from;
if (!to || !from || !*from) return;
/*
- * First, see if there are any passwords here, and
- * point "tailto" to the end of the "to" list.
+ * We're editing the "to" list while we're adding new
+ * attributes to it. We don't want the new attributes to
+ * be edited, so we create an intermediate list to hold
+ * them during the editing process.
*/
- tailto = to;
- if (*to) for (i = *to; i; i = i->next) {
- VERIFY_VP(i);
- if (!i->da->vendor &&
- (i->da->attr == PW_USER_PASSWORD ||
- i->da->attr == PW_CRYPT_PASSWORD))
- has_password = 1;
- tailto = &i->next;
- }
+ head_new = NULL;
+ tail_new = &head_new;
/*
- * Loop over the "from" list.
+ * We're looping over the "from" list, moving some
+ * attributes out, but leaving others in place.
*/
- for (i = *from; i; i = next) {
+ tail_from = from;
+ while ((i = *tail_from) != NULL) {
VERIFY_VP(i);
- next = i->next;
/*
- * If there was a password in the "to" list,
- * do not move any other password from the
- * "from" to the "to" list.
+ * We never move Fall-Through.
*/
- if (has_password && !i->da->vendor &&
- (i->da->attr == PW_USER_PASSWORD ||
- i->da->attr == PW_CRYPT_PASSWORD)) {
- tailfrom = i;
+ if (!i->da->vendor && i->da->attr == PW_FALL_THROUGH) {
+ tail_from = &(i->next);
continue;
}
+ /*
+ * Unlike previous versions, we treat all other
+ * attributes as normal. i.e. there's no special
+ * treatment for passwords or Hint.
+ */
+
switch (i->op) {
/*
- * These are COMPARISON attributes
- * from a check list, and are not
- * supposed to be copied!
+ * Anything else are operators which
+ * shouldn't occur. We ignore them, and
+ * leave them in place.
*/
- case T_OP_NE:
- case T_OP_GE:
- case T_OP_GT:
- case T_OP_LE:
- case T_OP_LT:
- case T_OP_CMP_TRUE:
- case T_OP_CMP_FALSE:
- case T_OP_CMP_EQ:
- case T_OP_REG_EQ:
- case T_OP_REG_NE:
- tailfrom = i;
- continue;
-
default:
- break;
- }
-
- /*
- * If the attribute is already present in "to",
- * do not move it from "from" to "to". We make
- * an exception for "Hint" which can appear multiple
- * times, and we never move "Fall-Through".
- */
- if (i->da->attr == PW_FALL_THROUGH ||
- (i->da->attr != PW_HINT && i->da->attr != PW_FRAMED_ROUTE)) {
-
+ tail_from = &(i->next);
+ continue;
- found = pairfind(*to, i->da->attr, i->da->vendor,
- TAG_ANY);
+ /*
+ * Add it to the "to" list, but only if
+ * it doesn't already exist.
+ */
+ case T_OP_EQ:
+ found = pairfind(*to, i->da->attr, i->da->vendor, TAG_ANY);
+ if (!found) goto do_add;
- switch (i->op) {
+ tail_from = &(i->next);
+ continue;
/*
- * If matching attributes are found,
- * delete them.
+ * Add it to the "to" list, and delete any attribute
+ * of the same vendor/attr which already exists.
*/
- case T_OP_SUB: /* -= */
- if (found) {
- if (!i->vp_strvalue[0] ||
- (strcmp(found->vp_strvalue,
- i->vp_strvalue) == 0)){
- pairdelete(to,
- found->da->attr,
- found->da->vendor,
- TAG_ANY);
-
- /*
- * 'tailto' may have been
- * deleted...
- */
- tailto = to;
- for(j = *to; j; j = j->next) {
- tailto = &j->next;
- }
- }
- }
- tailfrom = i;
- continue;
+ case T_OP_SET:
+ found = pairfind(*to, i->da->attr, i->da->vendor, TAG_ANY);
+ if (!found) goto do_add;
- case T_OP_EQ: /* = */
/*
- * FIXME: Tunnel attributes with
- * different tags are different
- * attributes.
+ * Do NOT call pairdelete() here,
+ * due to issues with re-writing
+ * "request->username".
+ *
+ * Everybody calls pairmove, and
+ * expects it to work. We can't
+ * update request->username here,
+ * so instead we over-write the
+ * vp that it's pointing to.
*/
- if (found) {
- tailfrom = i;
- continue; /* with the loop */
+ switch (found->da->type) {
+ VALUE_PAIR *j;
+
+ default:
+ j = found->next;
+ memcpy(found, i, sizeof(*found));
+ found->next = j;
+ break;
+
+ case PW_TYPE_TLV:
+ pairmemsteal(found, i->vp_tlv);
+ i->vp_tlv = NULL;
+ break;
+
+ case PW_TYPE_OCTETS:
+ pairmemsteal(found, i->vp_octets);
+ i->vp_octets = NULL;
+ break;
+
+ case PW_TYPE_STRING:
+ pairstrsteal(found, i->vp_strvalue);
+ i->vp_strvalue = NULL;
+ found->tag = i->tag;
+ break;
}
- break;
-
- /*
- * If a similar attribute is found,
- * replace it with the new one. Otherwise,
- * add the new one to the list.
- */
- case T_OP_SET: /* := */
- if (found) {
- VALUE_PAIR *mynext = found->next;
-
- /*
- * Do NOT call pairdelete()
- * here, due to issues with
- * re-writing "request->username".
- *
- * Everybody calls pairmove,
- * and expects it to work.
- * We can't update request->username
- * here, so instead we over-write
- * the vp that it's pointing to.
- */
- memcpy(found, i, sizeof(*found));
- found->next = mynext;
- pairdelete(&found->next,
- found->da->attr,
- found->da->vendor, TAG_ANY);
+ /*
+ * Delete *all* of the attributes
+ * of the same number.
+ */
+ pairdelete(&found->next,
+ found->da->attr,
+ found->da->vendor, TAG_ANY);
- /*
- * 'tailto' may have been
- * deleted...
- */
- for(j = found; j; j = j->next) {
- tailto = &j->next;
- }
- continue;
- }
- break;
+ /*
+ * Remove this attribute from the
+ * "from" list.
+ */
+ *tail_from = i->next;
+ i->next = NULL;
+ pairfree(&i);
+ continue;
- /*
- * Add the new element to the list, even
- * if similar ones already exist.
- */
- default:
- case T_OP_ADD: /* += */
- break;
- }
+ /*
+ * Move it from the old list and add it
+ * to the new list.
+ */
+ case T_OP_ADD:
+ do_add:
+ *tail_from = i->next;
+ i->next = NULL;
+ *tail_new = talloc_steal(ctx, i);
+ tail_new = &(i->next);
+ continue;
}
- if (tailfrom)
- tailfrom->next = next;
- else
- *from = next;
+ } /* loop over the "from" list. */
- /*
- * If ALL of the 'to' attributes have been deleted,
- * then ensure that the 'tail' is updated to point
- * to the head.
- */
- if (!*to) {
- tailto = to;
- }
- *tailto = i;
- if (i) {
- tailto = &i->next;
- i->next = NULL;
- (void) talloc_steal(ctx, i);
- }
- }
+ /*
+ * Take the "new" list, and append it to the "to" list.
+ */
+ pairadd(to, head_new);
}
/** Move matching pairs between VALUE_PAIR lists
* the input list to the output list.
*
* @note pairfree should be called on the head of the old list to free unmoved
- attributes (if they're no longer needed).
+ attributes (if they're no longer needed).
*
* @param[in] ctx for talloc
* @param[in,out] to destination list.
* @param[in] attr to match, if PW_VENDOR_SPECIFIC and vendor 0, only VSAs will
* be copied. If 0 and 0, all attributes will match
* @param[in] vendor to match.
- * @param[in] tag to match, TAG_ANY matches any tag, TAG_UNUSED matches tagless VPs.
+ * @param[in] tag to match, TAG_ANY matches any tag, TAG_NONE matches tagless VPs.
*/
void pairfilter(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from, unsigned int attr, unsigned int vendor, int8_t tag)
{
VERIFY_VP(i);
next = i->next;
- if ((tag != TAG_ANY) && i->da->flags.has_tag &&
- (i->tag != tag)) {
+ if (i->da->flags.has_tag && TAG_EQ(tag, i->tag)) {
continue;
}
static char const *hextab = "0123456789abcdef";
-bool pairparsevalue(VALUE_PAIR *vp, char const *value)
+/** Convert string value to native attribute value
+ *
+ * @param vp to assign value to.
+ * @param value string to convert. Binary safe for variable length values if len is provided.
+ * @param inlen may be 0 in which case strlen(len) is used to determine length, else inline
+ * should be the length of the string or sub string to parse.
+ * @return true on success, else false.
+ */
+int pairparsevalue(VALUE_PAIR *vp, char const *value, size_t inlen)
{
- char *p;
- char const *cp, *cs;
- int x;
- uint64_t y;
- size_t length;
DICT_VALUE *dval;
+ size_t len;
+ char buffer[256];
- if (!value) return false;
+ if (!value) return -1;
VERIFY_VP(vp);
/*
goto finish;
}
+ len = (inlen == 0) ? strlen(value) : inlen;
+
+ /*
+ * It's a variable length type so we just alloc a new buffer
+ * of size len and copy.
+ */
switch(vp->da->type) {
case PW_TYPE_STRING:
+ {
+ size_t vp_len;
+ char const *cp;
+ char *p;
+ int x;
+
/*
* Do escaping here
*/
- p = talloc_strdup(vp, value);
- vp->vp_strvalue = p;
- cp = value;
- length = 0;
+ vp->vp_strvalue = p = talloc_memdup(vp, value, len + 1);
+ p[len] = '\0';
+ talloc_set_type(p, char);
+ cp = value;
+ vp_len = 0;
while (*cp) {
char c = *cp++;
- if (c == '\\') {
- switch (*cp) {
- case 'r':
- c = '\r';
- cp++;
- break;
- case 'n':
- c = '\n';
- cp++;
- break;
- case 't':
- c = '\t';
- cp++;
- break;
- case '"':
- c = '"';
- cp++;
- break;
- case '\'':
- c = '\'';
- cp++;
- break;
- case '\\':
- c = '\\';
- cp++;
- break;
- case '`':
- c = '`';
- cp++;
- break;
- case '\0':
- c = '\\'; /* no cp++ */
- break;
- default:
- if ((cp[0] >= '0') &&
- (cp[0] <= '9') &&
- (cp[1] >= '0') &&
- (cp[1] <= '9') &&
- (cp[2] >= '0') &&
- (cp[2] <= '9') &&
- (sscanf(cp, "%3o", &x) == 1)) {
- c = x;
- cp += 3;
- } /* else just do '\\' */
- }
+ if (c == '\\') switch (*cp) {
+ case 'r':
+ c = '\r';
+ cp++;
+ break;
+ case 'n':
+ c = '\n';
+ cp++;
+ break;
+ case 't':
+ c = '\t';
+ cp++;
+ break;
+ case '"':
+ c = '"';
+ cp++;
+ break;
+ case '\'':
+ c = '\'';
+ cp++;
+ break;
+ case '\\':
+ c = '\\';
+ cp++;
+ break;
+ case '`':
+ c = '`';
+ cp++;
+ break;
+ case '\0':
+ c = '\\'; /* no cp++ */
+ break;
+ default:
+ if ((cp[0] >= '0') &&
+ (cp[0] <= '9') &&
+ (cp[1] >= '0') &&
+ (cp[1] <= '9') &&
+ (cp[2] >= '0') &&
+ (cp[2] <= '9') &&
+ (sscanf(cp, "%3o", &x) == 1)) {
+ c = x;
+ cp += 3;
+
+ } else if (cp[0]) {
+ /*
+ * \p --> p
+ */
+ c = *cp++;
+ } /* else at EOL \ --> \ */
}
*p++ = c;
- length++;
+ vp_len++;
}
*p = '\0';
- vp->length = length;
- break;
+ vp->length = vp_len;
+ }
+ goto finish;
+
+ /* raw octets: 0x01020304... */
+ case PW_TYPE_VSA:
+ if (strcmp(value, "ANY") == 0) {
+ vp->length = 0;
+ goto finish;
+ } /* else it's hex */
+
+ case PW_TYPE_OCTETS:
+ {
+ uint8_t *p;
- case PW_TYPE_IPADDR:
/*
- * FIXME: complain if hostname
- * cannot be resolved, or resolve later!
+ * No 0x prefix, just copy verbatim.
*/
- p = NULL;
- cs = value;
+ if ((len < 2) || (strncasecmp(value, "0x", 2) != 0)) {
+ pairmemcpy(vp, (uint8_t const *) value, len);
+ goto finish;
+ }
- {
- fr_ipaddr_t ipaddr;
- if (ip_hton(cs, AF_INET, &ipaddr) < 0) {
- fr_strerror_printf("Failed to find IP address for %s", cs);
- return false;
- }
+#ifdef WITH_ASCEND_BINARY
+ do_octets:
+#endif
+ len -= 2;
- vp->vp_ipaddr = ipaddr.ipaddr.ip4addr.s_addr;
+ /*
+ * Invalid.
+ */
+ if ((len & 0x01) != 0) {
+ fr_strerror_printf("Length of Hex String is not even, got %zu bytes", vp->length);
+ return -1;
}
- vp->length = 4;
+
+ vp->length = len >> 1;
+ p = talloc_array(vp, uint8_t, vp->length);
+ if (fr_hex2bin(p, value + 2, len) != vp->length) {
+ talloc_free(p);
+ fr_strerror_printf("Invalid hex data");
+ return -1;
+ }
+
+ vp->vp_octets = p;
+ }
+ goto finish;
+
+ case PW_TYPE_ABINARY:
+#ifdef WITH_ASCEND_BINARY
+ if ((len > 1) && (strncasecmp(value, "0x", 2) == 0)) goto do_octets;
+
+ if (ascend_parse_filter(vp, value, len) < 0 ) {
+ /* Allow ascend_parse_filter's strerror to bubble up */
+ return -1;
+ }
+ goto finish;
+#else
+ /*
+ * If Ascend binary is NOT defined,
+ * then fall through to raw octets, so that
+ * the user can at least make them by hand...
+ */
+ goto do_octets;
+#endif
+
+ /* don't use this! */
+ case PW_TYPE_TLV:
+ {
+ uint8_t *p;
+
+ if ((len < 2) || (len & 0x01) || (strncasecmp(value, "0x", 2) != 0)) {
+ fr_strerror_printf("Invalid TLV specification");
+ return -1;
+ }
+ len -= 2;
+
+ vp->length = len >> 1;
+ p = talloc_array(vp, uint8_t, vp->length);
+ if (!p) {
+ fr_strerror_printf("No memory");
+ return -1;
+ }
+ if (fr_hex2bin(p, value + 2, len) != vp->length) {
+ fr_strerror_printf("Invalid hex data in TLV");
+ return -1;
+ }
+
+ vp->vp_tlv = p;
+ }
+ goto finish;
+
+ case PW_TYPE_IPV4_ADDR:
+ {
+ fr_ipaddr_t addr;
+
+ if (fr_pton4(&addr, value, inlen, false, false) < 0) return -1;
+
+ /*
+ * We allow v4 addresses to have a /32 suffix as some databases (PostgreSQL)
+ * print them this way.
+ */
+ if (addr.prefix != 32) {
+ fr_strerror_printf("Invalid IPv4 mask length \"/%i\". Only \"/32\" permitted "
+ "for non-prefix types", addr.prefix);
+ return -1;
+ }
+
+ vp->vp_ipaddr = addr.ipaddr.ip4addr.s_addr;
+ vp->length = sizeof(vp->vp_ipaddr);
+ }
+ goto finish;
+
+ case PW_TYPE_IPV4_PREFIX:
+ {
+ fr_ipaddr_t addr;
+
+ if (fr_pton4(&addr, value, inlen, false, false) < 0) return -1;
+
+ vp->vp_ipv4prefix[1] = addr.prefix;
+ memcpy(vp->vp_ipv4prefix + 2, &addr.ipaddr.ip4addr.s_addr, sizeof(vp->vp_ipv4prefix) - 2);
+ vp->length = sizeof(vp->vp_ipv4prefix);
+ }
+ goto finish;
+
+ case PW_TYPE_IPV6_ADDR:
+ {
+ fr_ipaddr_t addr;
+
+ if (fr_pton6(&addr, value, inlen, false, false) < 0) return -1;
+
+ /*
+ * We allow v6 addresses to have a /128 suffix as some databases (PostgreSQL)
+ * print them this way.
+ */
+ if (addr.prefix != 128) {
+ fr_strerror_printf("Invalid IPv6 mask length \"/%i\". Only \"/128\" permitted "
+ "for non-prefix types", addr.prefix);
+ return -1;
+ }
+
+ memcpy(&vp->vp_ipv6addr, &addr.ipaddr.ip6addr.s6_addr, sizeof(vp->vp_ipv6addr));
+ vp->length = sizeof(vp->vp_ipv6addr);
+ }
+ goto finish;
+
+ case PW_TYPE_IPV6_PREFIX:
+ {
+ fr_ipaddr_t addr;
+
+ if (fr_pton6(&addr, value, inlen, false, false) < 0) return -1;
+
+ vp->vp_ipv6prefix[1] = addr.prefix;
+ memcpy(vp->vp_ipv6prefix + 2, &addr.ipaddr.ip6addr.s6_addr, sizeof(vp->vp_ipv6prefix) - 2);
+ vp->length = sizeof(vp->vp_ipv6prefix);
+ }
+ goto finish;
+
+ default:
break;
+ }
+
+ /*
+ * It's a fixed size type, copy to a temporary buffer and
+ * \0 terminate if insize >= 0.
+ */
+ if (inlen > 0) {
+ if (len >= sizeof(buffer)) {
+ fr_strerror_printf("Temporary buffer too small");
+ return -1;
+ }
+
+ memcpy(buffer, value, inlen);
+ buffer[inlen] = '\0';
+ value = buffer;
+ }
+ switch(vp->da->type) {
case PW_TYPE_BYTE:
+ {
+ char *p;
vp->length = 1;
/*
if (!*p) {
if (vp->vp_integer > 255) {
fr_strerror_printf("Byte value \"%s\" is larger than 255", value);
- return false;
+ return -1;
}
break;
}
- if (fr_whitespace_check(p)) break;
+ if (is_whitespace(p)) break;
+ }
goto check_for_value;
case PW_TYPE_SHORT:
+ {
+ char *p;
+
/*
* Note that ALL integers are unsigned!
*/
if (!*p) {
if (vp->vp_integer > 65535) {
fr_strerror_printf("Byte value \"%s\" is larger than 65535", value);
- return false;
+ return -1;
}
break;
}
- if (fr_whitespace_check(p)) break;
+ if (is_whitespace(p)) break;
+ }
goto check_for_value;
case PW_TYPE_INTEGER:
+ {
+ char *p;
+
/*
* Note that ALL integers are unsigned!
*/
vp->vp_integer = fr_strtoul(value, &p);
vp->length = 4;
if (!*p) break;
- if (fr_whitespace_check(p)) break;
+ if (is_whitespace(p)) break;
check_for_value:
/*
*/
if ((dval = dict_valbyname(vp->da->attr, vp->da->vendor, value)) == NULL) {
fr_strerror_printf("Unknown value '%s' for attribute '%s'", value, vp->da->name);
- return false;
+ return -1;
}
vp->vp_integer = dval->value;
+ }
break;
case PW_TYPE_INTEGER64:
+ {
+ uint64_t y;
+
/*
* Note that ALL integers are unsigned!
*/
if (sscanf(value, "%" PRIu64, &y) != 1) {
fr_strerror_printf("Invalid value '%s' for attribute '%s'",
value, vp->da->name);
- return false;
+ return -1;
}
vp->vp_integer64 = y;
vp->length = 8;
- length = strspn(value, "0123456789");
- if (fr_whitespace_check(value + length)) break;
+ }
break;
case PW_TYPE_DATE:
- {
- /*
- * time_t may be 64 bits, whule vp_date
- * MUST be 32-bits. We need an
- * intermediary variable to handle
- * the conversions.
- */
- time_t date;
-
- if (fr_get_time(value, &date) < 0) {
- fr_strerror_printf("failed to parse time string "
- "\"%s\"", value);
- return false;
- }
+ {
+ /*
+ * time_t may be 64 bits, whule vp_date
+ * MUST be 32-bits. We need an
+ * intermediary variable to handle
+ * the conversions.
+ */
+ time_t date;
- vp->vp_date = date;
+ if (fr_get_time(value, &date) < 0) {
+ fr_strerror_printf("failed to parse time string "
+ "\"%s\"", value);
+ return -1;
}
- vp->length = 4;
- break;
- case PW_TYPE_ABINARY:
-#ifdef WITH_ASCEND_BINARY
- if (strncasecmp(value, "0x", 2) == 0) {
- goto do_octets;
- }
+ vp->vp_date = date;
+ vp->length = 4;
+ }
- if (ascend_parse_filter(vp) < 0 ) {
- char buffer[256];
+ break;
- snprintf(buffer, sizeof(buffer), "failed to parse Ascend binary attribute '%s'", fr_strerror());
- fr_strerror_printf("%s", buffer);
- return false;
+ case PW_TYPE_IFID:
+ if (ifid_aton(value, (void *) &vp->vp_ifid) == NULL) {
+ fr_strerror_printf("Failed to parse interface-id string \"%s\"", value);
+ return -1;
}
+ vp->length = 8;
break;
+ case PW_TYPE_ETHERNET:
+ {
+ char const *c1, *c2, *cp;
+ size_t vp_len = 0;
+
/*
- * If Ascend binary is NOT defined,
- * then fall through to raw octets, so that
- * the user can at least make them by hand...
+ * Convert things which are obviously integers to Ethernet addresses
+ *
+ * We assume the number is the bigendian representation of the
+ * ethernet address.
*/
-#endif
- /* raw octets: 0x01020304... */
- case PW_TYPE_VSA:
- if (strcmp(value, "ANY") == 0) {
- vp->length = 0;
- break;
- } /* else it's hex */
-
- case PW_TYPE_OCTETS:
- if (strncasecmp(value, "0x", 2) == 0) {
- size_t size;
- uint8_t *us;
+ if (is_integer(value)) {
+ uint64_t integer = htonll(atoll(value));
-#ifdef WITH_ASCEND_BINARY
- do_octets:
-#endif
- cp = value + 2;
- size = strlen(cp);
- vp->length = size >> 1;
- us = talloc_array(vp, uint8_t, vp->length);
+ memcpy(&vp->vp_ether, &integer, sizeof(vp->vp_ether));
+ break;
+ }
- /*
- * Invalid.
- */
- if ((size & 0x01) != 0) {
- fr_strerror_printf("Hex string is not an even length string");
- return false;
- }
-
- if (fr_hex2bin(us, cp, vp->length) != vp->length) {
- fr_strerror_printf("Invalid hex data");
- return false;
- }
- vp->vp_octets = us;
- } else {
- pairstrcpy(vp, value);
- }
- break;
-
- case PW_TYPE_IFID:
- if (ifid_aton(value, (void *) &vp->vp_ifid) == NULL) {
- fr_strerror_printf("failed to parse interface-id "
- "string \"%s\"", value);
- return false;
- }
- vp->length = 8;
- break;
-
- case PW_TYPE_IPV6ADDR:
- {
- fr_ipaddr_t ipaddr;
-
- if (ip_hton(value, AF_INET6, &ipaddr) < 0) {
- char buffer[1024];
-
- strlcpy(buffer, fr_strerror(), sizeof(buffer));
-
- fr_strerror_printf("failed to parse IPv6 address "
- "string \"%s\": %s", value, buffer);
- return false;
- }
- vp->vp_ipv6addr = ipaddr.ipaddr.ip6addr;
- vp->length = 16; /* length of IPv6 address */
- }
- break;
-
- case PW_TYPE_IPV6PREFIX:
- p = strchr(value, '/');
- if (!p || ((p - value) >= 256)) {
- fr_strerror_printf("invalid IPv6 prefix "
- "string \"%s\"", value);
- return false;
- } else {
- unsigned int prefix;
- char buffer[256], *eptr;
-
- memcpy(buffer, value, p - value);
- buffer[p - value] = '\0';
-
- if (inet_pton(AF_INET6, buffer, vp->vp_ipv6prefix + 2) <= 0) {
- fr_strerror_printf("failed to parse IPv6 address "
- "string \"%s\"", value);
- return false;
- }
-
- prefix = strtoul(p + 1, &eptr, 10);
- if ((prefix > 128) || *eptr) {
- fr_strerror_printf("failed to parse IPv6 address "
- "string \"%s\"", value);
- return false;
- }
- vp->vp_ipv6prefix[1] = prefix;
- }
- vp->length = 16 + 2;
- break;
-
- case PW_TYPE_IPV4PREFIX:
- p = strchr(value, '/');
-
- /*
- * 192.0.2.2 is parsed as if it was /32
- */
- if (!p) {
- vp->vp_ipv4prefix[1] = 32;
-
- if (inet_pton(AF_INET, value, vp->vp_ipv4prefix + 2) <= 0) {
- fr_strerror_printf("failed to parse IPv4 address "
- "string \"%s\"", value);
- return false;
- }
- vp->length = sizeof(vp->vp_ipv4prefix);
- break;
- }
-
- /*
- * Otherwise parse the prefix
- */
- if ((p - value) >= 256) {
- fr_strerror_printf("invalid IPv4 prefix "
- "string \"%s\"", value);
- return false;
- } else {
- unsigned int prefix;
- char buffer[256], *eptr;
-
- memcpy(buffer, value, p - value);
- buffer[p - value] = '\0';
-
- if (inet_pton(AF_INET, buffer, vp->vp_ipv4prefix + 2) <= 0) {
- fr_strerror_printf("failed to parse IPv4 address "
- "string \"%s\"", value);
- return false;
- }
-
- prefix = strtoul(p + 1, &eptr, 10);
- if ((prefix > 32) || *eptr) {
- fr_strerror_printf("failed to parse IPv4 address "
- "string \"%s\"", value);
- return false;
+ cp = value;
+ while (*cp) {
+ if (cp[1] == ':') {
+ c1 = hextab;
+ c2 = memchr(hextab, tolower((int) cp[0]), 16);
+ cp += 2;
+ } else if ((cp[1] != '\0') && ((cp[2] == ':') || (cp[2] == '\0'))) {
+ c1 = memchr(hextab, tolower((int) cp[0]), 16);
+ c2 = memchr(hextab, tolower((int) cp[1]), 16);
+ cp += 2;
+ if (*cp == ':') cp++;
+ } else {
+ c1 = c2 = NULL;
}
- vp->vp_ipv4prefix[1] = prefix;
-
- if (prefix < 32) {
- uint32_t addr, mask;
-
- memcpy(&addr, vp->vp_ipv4prefix + 2, sizeof(addr));
- mask = 1;
- mask <<= (32 - prefix);
- mask--;
- mask = ~mask;
- mask = htonl(mask);
- addr &= mask;
- memcpy(vp->vp_ipv4prefix + 2, &addr, sizeof(addr));
+ if (!c1 || !c2 || (vp_len >= sizeof(vp->vp_ether))) {
+ fr_strerror_printf("failed to parse Ethernet address \"%s\"", value);
+ return -1;
}
+ vp->vp_ether[vp_len] = ((c1-hextab)<<4) + (c2-hextab);
+ vp_len++;
}
- vp->length = sizeof(vp->vp_ipv4prefix);
- break;
- case PW_TYPE_ETHERNET:
- {
- char const *c1, *c2;
-
- length = 0;
- cp = value;
- while (*cp) {
- if (cp[1] == ':') {
- c1 = hextab;
- c2 = memchr(hextab, tolower((int) cp[0]), 16);
- cp += 2;
- } else if ((cp[1] != '\0') &&
- ((cp[2] == ':') ||
- (cp[2] == '\0'))) {
- c1 = memchr(hextab, tolower((int) cp[0]), 16);
- c2 = memchr(hextab, tolower((int) cp[1]), 16);
- cp += 2;
- if (*cp == ':') cp++;
- } else {
- c1 = c2 = NULL;
- }
- if (!c1 || !c2 || (length >= sizeof(vp->vp_ether))) {
- fr_strerror_printf("failed to parse Ethernet address \"%s\"", value);
- return false;
- }
- vp->vp_ether[length] = ((c1-hextab)<<4) + (c2-hextab);
- length++;
- }
- }
vp->length = 6;
+ }
break;
/*
* These are not dynamic da, and will have the same vendor
* and attribute as the original.
*/
- case PW_TYPE_COMBO_IP:
- {
- DICT_ATTR const *da;
-
- if (inet_pton(AF_INET6, value, &vp->vp_ipv6addr) > 0) {
- da = dict_attrbytype(vp->da->attr, vp->da->vendor,
- PW_TYPE_IPV6ADDR);
- if (!da) {
- return false;
- }
+ case PW_TYPE_IP_ADDR:
+ {
+ DICT_ATTR const *da;
- vp->length = 16; /* length of IPv6 address */
- } else {
- fr_ipaddr_t ipaddr;
+ if (inet_pton(AF_INET6, value, &vp->vp_ipv6addr) > 0) {
+ da = dict_attrbytype(vp->da->attr, vp->da->vendor, PW_TYPE_IPV6_ADDR);
+ if (!da) {
+ fr_strerror_printf("Cannot find ipv6addr for %s", vp->da->name);
+ return -1;
+ }
- da = dict_attrbytype(vp->da->attr, vp->da->vendor,
- PW_TYPE_IPADDR);
- if (!da) {
- return false;
- }
+ vp->length = 16; /* length of IPv6 address */
+ } else {
+ fr_ipaddr_t ipaddr;
- if (ip_hton(value, AF_INET, &ipaddr) < 0) {
- fr_strerror_printf("Failed to find IPv4 address for %s", value);
- return false;
- }
+ da = dict_attrbytype(vp->da->attr, vp->da->vendor,
+ PW_TYPE_IPV4_ADDR);
+ if (!da) {
+ fr_strerror_printf("Cannot find ipaddr for %s", vp->da->name);
+ return -1;
+ }
- vp->vp_ipaddr = ipaddr.ipaddr.ip4addr.s_addr;
- vp->length = 4;
+ if (ip_hton(&ipaddr, AF_INET, value, false) < 0) {
+ fr_strerror_printf("Failed to find IPv4 address for %s", value);
+ return -1;
}
- vp->da = da;
+ vp->vp_ipaddr = ipaddr.ipaddr.ip4addr.s_addr;
+ vp->length = 4;
}
- break;
- case PW_TYPE_SIGNED: /* Damned code for 1 WiMAX attribute */
- vp->vp_signed = (int32_t) strtol(value, &p, 10);
- vp->length = 4;
+ vp->da = da;
+ }
break;
- case PW_TYPE_TLV: /* don't use this! */
- if (strncasecmp(value, "0x", 2) != 0) {
- fr_strerror_printf("Invalid TLV specification");
- return false;
- }
- length = strlen(value + 2) / 2;
- if (vp->length < length) {
- TALLOC_FREE(vp->vp_tlv);
- }
- vp->vp_tlv = talloc_array(vp, uint8_t, length);
- if (!vp->vp_tlv) {
- fr_strerror_printf("No memory");
- return false;
- }
- if (fr_hex2bin(vp->vp_tlv, value + 2, length) != length) {
- fr_strerror_printf("Invalid hex data in TLV");
- return false;
- }
- vp->length = length;
+ case PW_TYPE_SIGNED:
+ /* Damned code for 1 WiMAX attribute */
+ vp->vp_signed = (int32_t) strtol(value, NULL, 10);
+ vp->length = 4;
break;
/*
*/
default:
fr_strerror_printf("unknown attribute type %d", vp->da->type);
- return false;
+ return -1;
}
- finish:
+finish:
vp->type = VT_DATA;
- return true;
+ return 0;
+}
+
+/** Use simple heuristics to create an VALUE_PAIR from an unknown address string
+ *
+ * If a DICT_ATTR is not provided for the address type, parsing will fail with
+ * and error.
+ *
+ * @param ctx to allocate VP in.
+ * @param value IPv4/IPv6 address/prefix string.
+ * @param ipv4 dictionary attribute to use for an IPv4 address.
+ * @param ipv6 dictionary attribute to use for an IPv6 address.
+ * @param ipv4_prefix dictionary attribute to use for an IPv4 prefix.
+ * @param ipv6_prefix dictionary attribute to use for an IPv6 prefix.
+ * @return NULL on error, or new VALUE_PAIR.
+ */
+VALUE_PAIR *pairmake_ip(TALLOC_CTX *ctx, char const *value, DICT_ATTR *ipv4, DICT_ATTR *ipv6,
+ DICT_ATTR *ipv4_prefix, DICT_ATTR *ipv6_prefix)
+{
+ VALUE_PAIR *vp;
+ DICT_ATTR *da = NULL;
+
+ if (!fr_assert(ipv4 || ipv6 || ipv4_prefix || ipv6_prefix)) {
+ return NULL;
+ }
+
+ /* No point in repeating the work of pairparsevalue */
+ if (strchr(value, ':')) {
+ if (strchr(value, '/')) {
+ da = ipv6_prefix;
+ goto finish;
+ }
+
+ da = ipv6;
+ goto finish;
+ }
+
+ if (strchr(value, '/')) {
+ da = ipv4_prefix;
+ goto finish;
+ }
+
+ if (ipv4) {
+ da = ipv4;
+ goto finish;
+ }
+
+ fr_strerror_printf("Invalid IP value specified, allowed types are %s%s%s%s",
+ ipv4 ? "ipaddr " : "", ipv6 ? "ipv6addr " : "",
+ ipv4_prefix ? "ipv4prefix " : "", ipv6_prefix ? "ipv6prefix" : "");
+
+finish:
+ vp = pairalloc(ctx, da);
+ if (!vp) return NULL;
+ if (pairparsevalue(vp, value, 0) < 0) {
+ talloc_free(vp);
+ return NULL;
+ }
+
+ return vp;
}
+
/** Create a valuepair from an ASCII attribute and value
*
* Where the attribute name is in the form:
VALUE_PAIR *vp;
char *tc, *ts;
int8_t tag;
- int found_tag;
+ bool found_tag;
char buffer[256];
char const *attrname = attribute;
/*
* Check for tags in 'Attribute:Tag' format.
*/
- found_tag = 0;
- tag = 0;
+ found_tag = false;
+ tag = TAG_ANY;
ts = strrchr(attribute, ':');
if (ts && !ts[1]) {
if (ts[1] == '*' && ts[2] == 0) {
/* Wildcard tag for check items */
tag = TAG_ANY;
- *ts = 0;
+ *ts = '\0';
} else if ((ts[1] >= '0') && (ts[1] <= '9')) {
/* It's not a wild card tag */
tag = strtol(ts + 1, &tc, 0);
if (tc && !*tc && TAG_VALID_ZERO(tag))
- *ts = 0;
- else tag = 0;
+ *ts = '\0';
+ else tag = TAG_ANY;
} else {
fr_strerror_printf("Invalid tag for attribute %s", attribute);
return NULL;
}
- found_tag = 1;
+ found_tag = true;
}
/*
}
vp = pairalloc(ctx, da);
- if (!vp) {
- return NULL;
- }
-
+ if (!vp) return NULL;
vp->op = (op == 0) ? T_OP_EQ : op;
vp->tag = tag;
switch (vp->op) {
- default:
- break;
-
case T_OP_CMP_TRUE:
case T_OP_CMP_FALSE:
vp->vp_strvalue = NULL;
*/
case T_OP_REG_EQ: /* =~ */
case T_OP_REG_NE: /* !~ */
+ {
+
+ int compare;
+ regex_t reg;
#ifndef WITH_REGEX
fr_strerror_printf("Regular expressions are not supported");
return NULL;
talloc_free(vp);
- if (1) {
- int compare;
- regex_t reg;
-
- compare = regcomp(®, value, REG_EXTENDED);
- if (compare != 0) {
- regerror(compare, ®, buffer, sizeof(buffer));
- fr_strerror_printf("Illegal regular expression in attribute: %s: %s",
+ compare = regcomp(®, value, REG_EXTENDED);
+ if (compare != 0) {
+ regerror(compare, ®, buffer, sizeof(buffer));
+ fr_strerror_printf("Illegal regular expression in attribute: %s: %s",
attribute, buffer);
- return NULL;
- }
+ return NULL;
}
+ regfree(®);
vp = pairmake(ctx, NULL, attribute, NULL, op);
if (!vp) return NULL;
break;
#endif
}
+ default:
+ break;
+ }
/*
* FIXME: if (strcasecmp(attribute, vp->da->name) != 0)
* We probably want to fix pairparsevalue to accept
* octets as values for any attribute.
*/
- if (value && !pairparsevalue(vp, value)) {
+ if (value && (pairparsevalue(vp, value, 0) < 0)) {
talloc_free(vp);
return NULL;
}
return -1;
}
- raw = talloc_strdup(vp, value);
+ raw = talloc_typed_strdup(vp, value);
if (!raw) {
return -1;
}
*ptr = p;
/* Now we should have an operator here. */
- raw->op = gettoken(ptr, buf, sizeof(buf));
+ raw->op = gettoken(ptr, buf, sizeof(buf), false);
if (raw->op < T_EQSTART || raw->op > T_EQEND) {
fr_strerror_printf("Expecting operator");
/*
* Read value. Note that empty string values are allowed
*/
- quote = gettoken(ptr, raw->r_opand, sizeof(raw->r_opand));
+ quote = gettoken(ptr, raw->r_opand, sizeof(raw->r_opand), false);
if (quote == T_EOL) {
fr_strerror_printf("Failed to get value");
*/
p = *ptr;
- next = gettoken(&p, buf, sizeof(buf));
+ next = gettoken(&p, buf, sizeof(buf), false);
switch (next) {
case T_EOL:
case T_HASH:
/*
* We allow an empty line.
*/
- if (buffer[0] == 0)
+ if (buffer[0] == 0) {
return T_EOL;
+ }
head = NULL;
tail = &head;
}
if (pairmark_xlat(vp, raw.r_opand) < 0) {
talloc_free(vp);
-
+ last_token = T_OP_INVALID;
break;
}
} else {
/*
* Read valuepairs from the fp up to End-Of-File.
- *
- * Hmm... this function is only used by radclient..
*/
-VALUE_PAIR *readvp2(TALLOC_CTX *ctx, FILE *fp, int *pfiledone, char const *errprefix)
+int readvp2(VALUE_PAIR **out, TALLOC_CTX *ctx, FILE *fp, bool *pfiledone)
{
char buf[8192];
FR_TOKEN last_token = T_EOL;
- VALUE_PAIR *vp;
- VALUE_PAIR *list;
- int error = 0;
- list = NULL;
+ vp_cursor_t cursor;
+
+ VALUE_PAIR *vp = NULL;
+
+ fr_cursor_init(&cursor, out);
- while (!error && fgets(buf, sizeof(buf), fp) != NULL) {
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
/*
* If we get a '\n' by itself, we assume that's
* the end of that VP
*/
- if ((buf[0] == '\n') && (list)) {
- return list;
- }
- if ((buf[0] == '\n') && (!list)) {
+ if (buf[0] == '\n') {
+ if (vp) return 0;
continue;
}
vp = NULL;
last_token = userparse(ctx, buf, &vp);
if (!vp) {
- if (last_token != T_EOL) {
- fr_perror("%s", errprefix);
- error = 1;
- break;
- }
+ if (last_token != T_EOL) goto error;
break;
}
- pairadd(&list, vp);
+ fr_cursor_insert(&cursor, vp);
buf[0] = '\0';
}
- if (error) pairfree(&list);
+ *pfiledone = true;
+
+ return 0;
+
+error:
+ vp = fr_cursor_first(&cursor);
+ if (vp) pairfree(&vp);
+
+ return -1;
+}
+
+/** Compare two attribute values
+ *
+ * @param[in] one the first attribute.
+ * @param[in] two the second attribute.
+ * @return -1 if one is less than two, 0 if both are equal, 1 if one is more than two, < -1 on error.
+ */
+int8_t paircmp_value(VALUE_PAIR const *one, VALUE_PAIR const *two)
+{
+ int64_t compare = 0;
+
+ VERIFY_VP(one);
+ VERIFY_VP(two);
+
+ if (one->da->type != two->da->type) {
+ fr_strerror_printf("Can't compare attribute values of different types");
+ return -2;
+ }
+
+ /*
+ * After doing the previous check for special comparisons,
+ * do the per-type comparison here.
+ */
+ switch (one->da->type) {
+ case PW_TYPE_ABINARY:
+ case PW_TYPE_OCTETS:
+ {
+ size_t length;
+
+ if (one->length > two->length) {
+ length = one->length;
+ } else {
+ length = two->length;
+ }
+
+ if (length) {
+ compare = memcmp(one->vp_octets, two->vp_octets, length);
+ if (compare != 0) break;
+ }
+
+ /*
+ * Contents are the same. The return code
+ * is therefore the difference in lengths.
+ *
+ * i.e. "0x00" is smaller than "0x0000"
+ */
+ compare = one->length - two->length;
+ }
+ break;
+
+ case PW_TYPE_STRING:
+ fr_assert(one->vp_strvalue);
+ fr_assert(two->vp_strvalue);
+ compare = strcmp(one->vp_strvalue, two->vp_strvalue);
+ break;
+
+ case PW_TYPE_BOOLEAN:
+ case PW_TYPE_BYTE:
+ case PW_TYPE_SHORT:
+ case PW_TYPE_INTEGER:
+ case PW_TYPE_DATE:
+ compare = (int64_t) one->vp_integer - (int64_t) two->vp_integer;
+ break;
+
+ case PW_TYPE_SIGNED:
+ compare = one->vp_signed - two->vp_signed;
+ break;
+
+ case PW_TYPE_INTEGER64:
+ /*
+ * Don't want integer overflow!
+ */
+ if (one->vp_integer64 < two->vp_integer64) {
+ compare = -1;
+ } else if (one->vp_integer64 > two->vp_integer64) {
+ compare = 1;
+ }
+ break;
+
+ case PW_TYPE_ETHERNET:
+ compare = memcmp(&one->vp_ether, &two->vp_ether, sizeof(one->vp_ether));
+ break;
- *pfiledone = 1;
+ case PW_TYPE_IPV4_ADDR:
+ compare = (int64_t) ntohl(one->vp_ipaddr) - (int64_t) ntohl(two->vp_ipaddr);
+ break;
- return error ? NULL: list;
+ case PW_TYPE_IPV6_ADDR:
+ compare = memcmp(&one->vp_ipv6addr, &two->vp_ipv6addr, sizeof(one->vp_ipv6addr));
+ break;
+
+ case PW_TYPE_IPV6_PREFIX:
+ compare = memcmp(&one->vp_ipv6prefix, &two->vp_ipv6prefix, sizeof(one->vp_ipv6prefix));
+ break;
+
+ case PW_TYPE_IPV4_PREFIX:
+ compare = memcmp(&one->vp_ipv4prefix, &two->vp_ipv4prefix, sizeof(one->vp_ipv4prefix));
+ break;
+
+ case PW_TYPE_IFID:
+ compare = memcmp(&one->vp_ifid, &two->vp_ifid, sizeof(one->vp_ifid));
+ break;
+
+ /*
+ * None of the types below should be in the REQUEST
+ */
+ case PW_TYPE_INVALID: /* We should never see these */
+ case PW_TYPE_IP_ADDR: /* This should of been converted into IPADDR/IPV6ADDR */
+ case PW_TYPE_IP_PREFIX: /* This should of been converted into IPADDR/IPV6ADDR */
+ case PW_TYPE_TLV:
+ case PW_TYPE_EXTENDED:
+ case PW_TYPE_LONG_EXTENDED:
+ case PW_TYPE_EVS:
+ case PW_TYPE_VSA:
+ case PW_TYPE_TIMEVAL:
+ case PW_TYPE_MAX:
+ fr_assert(0); /* unknown type */
+ return -2;
+
+ /*
+ * Do NOT add a default here, as new types are added
+ * static analysis will warn us they're not handled
+ */
+ }
+
+ if (compare > 0) {
+ return 1;
+ } else if (compare < 0) {
+ return -1;
+ }
+ return 0;
}
/*
*
* reserved, prefix-len, data...
*/
-static int paircmp_cidr(FR_TOKEN op, int bytes, uint8_t const *one, uint8_t const *two)
+static int paircmp_op_cidr(FR_TOKEN op, int bytes,
+ uint8_t one_net, uint8_t const *one,
+ uint8_t two_net, uint8_t const *two)
{
int i, common;
uint32_t mask;
/*
* Handle the case of netmasks being identical.
*/
- if (one[1] == two[1]) {
+ if (one_net == two_net) {
int compare;
- compare = memcmp(one + 2, two + 2, bytes);
+ compare = memcmp(one, two, bytes);
/*
* If they're identical return true for
case T_OP_LE:
case T_OP_LT: /* 192/8 < 192.168/16 --> false */
- if (one[1] < two[1]) {
+ if (one_net < two_net) {
return false;
}
break;
case T_OP_GE:
case T_OP_GT: /* 192/16 > 192.168/8 --> false */
- if (one[1] > two[1]) {
+ if (one_net > two_net) {
return false;
}
break;
return false;
}
- if (one[1] < two[1]) {
- common = one[1];
+ if (one_net < two_net) {
+ common = one_net;
} else {
- common = two[1];
+ common = two_net;
}
/*
* identical, it MAY be a match. If they're different,
* it is NOT a match.
*/
- i = 2;
- while (i < (2 + bytes)) {
+ i = 0;
+ while (i < bytes) {
/*
* All leading bytes are identical.
*/
return false;
}
-/*
- * Compare two pairs, using the operator from "one".
+/** Compare two attributes using an operator
+ *
+ * @param[in] a the first attribute
+ * @param[in] op the operator for comparison.
+ * @param[in] b the second attribute
+ * @return 1 if true, 0 if false, -1 on error.
+ */
+int8_t paircmp_op(VALUE_PAIR const *a, FR_TOKEN op, VALUE_PAIR const *b)
+{
+ int compare;
+
+ if (!a || !b) return -1;
+
+ switch (a->da->type) {
+ case PW_TYPE_IPV4_ADDR:
+ switch (b->da->type) {
+ case PW_TYPE_IPV4_ADDR: /* IPv4 and IPv4 */
+ goto cmp;
+
+ case PW_TYPE_IPV4_PREFIX: /* IPv4 and IPv4 Prefix */
+ return paircmp_op_cidr(op, 4, 32, (uint8_t const *) &a->vp_ipaddr,
+ b->vp_ipv4prefix[1], (uint8_t const *) &b->vp_ipv4prefix + 2);
+
+ default:
+ fr_strerror_printf("Cannot compare IPv4 with IPv6 address");
+ return -1;
+ }
+ break;
+
+ case PW_TYPE_IPV4_PREFIX: /* IPv4 and IPv4 Prefix */
+ switch (b->da->type) {
+ case PW_TYPE_IPV4_ADDR:
+ return paircmp_op_cidr(op, 4, a->vp_ipv4prefix[1],
+ (uint8_t const *) &a->vp_ipv4prefix + 2,
+ 32, (uint8_t const *) &b->vp_ipaddr);
+
+ case PW_TYPE_IPV4_PREFIX: /* IPv4 Prefix and IPv4 Prefix */
+ return paircmp_op_cidr(op, 4, a->vp_ipv4prefix[1],
+ (uint8_t const *) &a->vp_ipv4prefix + 2,
+ b->vp_ipv4prefix[1], (uint8_t const *) &b->vp_ipv4prefix + 2);
+
+ default:
+ fr_strerror_printf("Cannot compare IPv4 with IPv6 address");
+ return -1;
+ }
+ break;
+
+ case PW_TYPE_IPV6_ADDR:
+ switch (b->da->type) {
+ case PW_TYPE_IPV6_ADDR: /* IPv6 and IPv6 */
+ goto cmp;
+
+ case PW_TYPE_IPV6_PREFIX: /* IPv6 and IPv6 Preifx */
+ return paircmp_op_cidr(op, 16, 128, (uint8_t const *) &a->vp_ipv6addr,
+ b->vp_ipv6prefix[1], (uint8_t const *) &b->vp_ipv6prefix + 2);
+ break;
+
+ default:
+ fr_strerror_printf("Cannot compare IPv6 with IPv4 address");
+ return -1;
+ }
+ break;
+
+ case PW_TYPE_IPV6_PREFIX:
+ switch (b->da->type) {
+ case PW_TYPE_IPV6_ADDR: /* IPv6 Prefix and IPv6 */
+ return paircmp_op_cidr(op, 16, a->vp_ipv6prefix[1],
+ (uint8_t const *) &a->vp_ipv6prefix + 2,
+ 128, (uint8_t const *) &b->vp_ipv6addr);
+
+ case PW_TYPE_IPV6_PREFIX: /* IPv6 Prefix and IPv6 */
+ return paircmp_op_cidr(op, 16, a->vp_ipv6prefix[1],
+ (uint8_t const *) &a->vp_ipv6prefix + 2,
+ b->vp_ipv6prefix[1], (uint8_t const *) &b->vp_ipv6prefix + 2);
+
+ default:
+ fr_strerror_printf("Cannot compare IPv6 with IPv4 address");
+ return -1;
+ }
+ break;
+
+ default:
+ cmp:
+ compare = paircmp_value(a, b);
+ if (compare < -1) { /* comparison error */
+ return -1;
+ }
+ }
+
+ /*
+ * Now do the operator comparison.
+ */
+ switch (op) {
+ case T_OP_CMP_EQ:
+ return (compare == 0);
+
+ case T_OP_NE:
+ return (compare != 0);
+
+ case T_OP_LT:
+ return (compare < 0);
+
+ case T_OP_GT:
+ return (compare > 0);
+
+ case T_OP_LE:
+ return (compare <= 0);
+
+ case T_OP_GE:
+ return (compare >= 0);
+
+ default:
+ return 0;
+ }
+}
+
+/** Compare two pairs, using the operator from "a"
*
* i.e. given two attributes, it does:
*
- * (two->data) (one->operator) (one->data)
+ * (b->data) (a->operator) (a->data)
*
* e.g. "foo" != "bar"
*
- * Returns true (comparison is true), or false (comparison is not true);
+ * @param[in] a the first attribute
+ * @param[in] b the second attribute
+ * @return 1 if true, 0 if false, -1 on error.
*/
-int paircmp(VALUE_PAIR *one, VALUE_PAIR *two)
+int8_t paircmp(VALUE_PAIR *a, VALUE_PAIR *b)
{
- int compare;
+ if (!a) return -1;
- VERIFY_VP(one);
- VERIFY_VP(two);
+ VERIFY_VP(a);
+ if (b) VERIFY_VP(b);
- switch (one->op) {
+ switch (a->op) {
case T_OP_CMP_TRUE:
- return (two != NULL);
+ return (b != NULL);
case T_OP_CMP_FALSE:
- return (two == NULL);
+ return (b == NULL);
/*
- * One is a regex, compile it, print two to a string,
+ * a is a regex, compile it, print b to a string,
* and then do string comparisons.
*/
case T_OP_REG_EQ:
return -1;
#else
{
+ int compare;
regex_t reg;
char buffer[MAX_STRING_LEN * 4 + 1];
- compare = regcomp(®, one->vp_strvalue, REG_EXTENDED);
+ compare = regcomp(®, a->vp_strvalue, REG_EXTENDED);
if (compare != 0) {
regerror(compare, ®, buffer, sizeof(buffer));
fr_strerror_printf("Illegal regular expression in attribute: %s: %s",
- one->da->name, buffer);
+ a->da->name, buffer);
+ return -1;
+ }
+
+ if (!b) {
+ regfree(®);
return -1;
}
- vp_prints_value(buffer, sizeof(buffer), two, 0);
+ vp_prints_value(buffer, sizeof(buffer), b, 0);
/*
* Don't care about substring matches,
compare = regexec(®, buffer, 0, NULL, 0);
regfree(®);
- if (one->op == T_OP_REG_EQ) return (compare == 0);
+ if (a->op == T_OP_REG_EQ) {
+ return (compare == 0);
+ }
+
return (compare != 0);
}
#endif
break;
}
- return paircmp_op(two, one->op, one);
+ return paircmp_op(b, a->op, a);
}
-/* Compare two attributes
+/** Determine equality of two lists
+ *
+ * This is useful for comparing lists of attributes inserted into a binary tree.
*
- * @param[in] one the first attribute
- * @param[in] op the operator for comparison
- * @param[in] two the second attribute
- * @return true if ONE OP TWO is true, else false.
+ * @param a first list of VALUE_PAIRs.
+ * @param b second list of VALUE_PAIRs.
+ * @return -1 if a < b, 0 if the two lists are equal, 1 if a > b, -2 on error.
*/
-int paircmp_op(VALUE_PAIR const *one, FR_TOKEN op, VALUE_PAIR const *two)
+int8_t pairlistcmp(VALUE_PAIR *a, VALUE_PAIR *b)
{
- int compare;
-
- VERIFY_VP(one);
- VERIFY_VP(two);
-
- /*
- * Can't compare two attributes of differing types
- *
- * FIXME: maybe do checks for IP OP IP/mask ??
- */
- if (one->da->type != two->da->type) {
- return one->da->type - two->da->type;
- }
-
- /*
- * After doing the previous check for special comparisons,
- * do the per-type comparison here.
- */
- switch (one->da->type) {
- case PW_TYPE_ABINARY:
- case PW_TYPE_OCTETS:
- {
- size_t length;
-
- if (one->length > two->length) {
- length = one->length;
- } else {
- length = two->length;
+ vp_cursor_t a_cursor, b_cursor;
+ VALUE_PAIR *a_p, *b_p;
+ int ret;
+
+ for (a_p = fr_cursor_init(&a_cursor, &a), b_p = fr_cursor_init(&b_cursor, &b);
+ a_p && b_p;
+ a_p = fr_cursor_next(&a_cursor), b_p = fr_cursor_next(&b_cursor)) {
+ /* Same VP, no point doing expensive checks */
+ if (a_p == b_p) {
+ continue;
}
- if (length) {
- compare = memcmp(one->vp_octets, two->vp_octets,
- length);
- if (compare != 0) break;
+ if (a_p->da < b_p->da) {
+ return -1;
}
-
- /*
- * Contents are the same. The return code
- * is therefore the difference in lengths.
- *
- * i.e. "0x00" is smaller than "0x0000"
- */
- compare = one->length - two->length;
- }
- break;
-
- case PW_TYPE_STRING:
- compare = strcmp(one->vp_strvalue, two->vp_strvalue);
- break;
-
- case PW_TYPE_BYTE:
- case PW_TYPE_SHORT:
- case PW_TYPE_INTEGER:
- case PW_TYPE_DATE:
- if (one->vp_integer < two->vp_integer) {
- compare = -1;
- } else if (one->vp_integer == two->vp_integer) {
- compare = 0;
- } else {
- compare = +1;
+ if (a_p->da > b_p->da) {
+ return 1;
}
- break;
- case PW_TYPE_INTEGER64:
- /*
- * Don't want integer overflow!
- */
- if (one->vp_integer64 < two->vp_integer64) {
- compare = -1;
- } else if (one->vp_integer64 > two->vp_integer64) {
- compare = +1;
- } else {
- compare = 0;
+ if (a_p->tag < b_p->tag) {
+ return -1;
}
- break;
- case PW_TYPE_IPADDR:
- if (ntohl(one->vp_ipaddr) < ntohl(two->vp_ipaddr)) {
- compare = -1;
- } else if (one->vp_ipaddr == two->vp_ipaddr) {
- compare = 0;
- } else {
- compare = +1;
+ if (a_p->tag > b_p->tag) {
+ return 1;
}
- break;
-
- case PW_TYPE_IPV6ADDR:
- compare = memcmp(&one->vp_ipv6addr, &two->vp_ipv6addr,
- sizeof(one->vp_ipv6addr));
- break;
- case PW_TYPE_IPV6PREFIX:
- return paircmp_cidr(op, 16,
- (uint8_t const *) &one->vp_ipv6prefix,
- (uint8_t const *) &two->vp_ipv6prefix);
-
- case PW_TYPE_IPV4PREFIX:
- return paircmp_cidr(op, 4,
- (uint8_t const *) &one->vp_ipv4prefix,
- (uint8_t const *) &two->vp_ipv4prefix);
-
- case PW_TYPE_IFID:
- compare = memcmp(&one->vp_ifid, &two->vp_ifid,
- sizeof(one->vp_ifid));
- break;
-
- default:
- return 0; /* unknown type */
+ ret = paircmp_value(a_p, b_p);
+ if (ret != 0) {
+ fr_assert(ret >= -1); /* Comparison error */
+ return ret;
+ }
}
- /*
- * Now do the operator comparison.
- */
- switch (op) {
- case T_OP_CMP_EQ:
- return (compare == 0);
+ if (!a_p && !b_p) {
+ return 0;
+ }
- case T_OP_NE:
- return (compare != 0);
+ if (!a_p) {
+ return -1;
+ }
- case T_OP_LT:
- return (compare < 0);
+ /* if(!b_p) */
+ return 1;
+}
- case T_OP_GT:
- return (compare > 0);
+/** Set the type of the VALUE_PAIR value buffer to match it's DICT_ATTR
+ *
+ * @param vp to fixup.
+ */
+static void pairtypeset(VALUE_PAIR *vp)
+{
+ if (!vp->data.ptr) return;
- case T_OP_LE:
- return (compare <= 0);
+ switch(vp->da->type) {
+ case PW_TYPE_OCTETS:
+ case PW_TYPE_TLV:
+ talloc_set_type(vp->data.ptr, uint8_t);
+ return;
- case T_OP_GE:
- return (compare >= 0);
+ case PW_TYPE_STRING:
+ talloc_set_type(vp->data.ptr, char);
+ return;
default:
- return 0;
+ return;
}
-
- return 0;
}
/** Copy data into an "octets" data type.
*
* @param[in,out] vp to update
* @param[in] src data to copy
- * @param[in] size of the data
+ * @param[in] size of the data, may be 0 in which case previous value will be freed.
*/
void pairmemcpy(VALUE_PAIR *vp, uint8_t const *src, size_t size)
{
- uint8_t *p, *q;
+ uint8_t *p = NULL, *q;
VERIFY_VP(vp);
- p = talloc_memdup(vp, src, size);
- if (!p) return;
+ if (size > 0) {
+ p = talloc_memdup(vp, src, size);
+ if (!p) return;
+ talloc_set_type(p, uint8_t);
+ }
memcpy(&q, &vp->vp_octets, sizeof(q));
- talloc_free(q);
+ TALLOC_FREE(q);
vp->vp_octets = p;
vp->length = size;
+
+ if (size > 0) pairtypeset(vp);
}
/** Reparent an allocated octet buffer to a VALUE_PAIR
* @param[in,out] vp to update
* @param[in] src buffer to steal.
*/
-void pairmemsteal(VALUE_PAIR *vp, uint8_t *src)
+void pairmemsteal(VALUE_PAIR *vp, uint8_t const *src)
{
uint8_t *q;
+
VERIFY_VP(vp);
memcpy(&q, &vp->vp_octets, sizeof(q));
vp->vp_octets = talloc_steal(vp, src);
vp->type = VT_DATA;
- vp->length = talloc_array_length(vp->vp_octets);
+ vp->length = talloc_array_length(vp->vp_strvalue);
+ pairtypeset(vp);
}
/** Reparent an allocated char buffer to a VALUE_PAIR
* @param[in,out] vp to update
* @param[in] src buffer to steal.
*/
-void pairstrsteal(VALUE_PAIR *vp, char *src)
+void pairstrsteal(VALUE_PAIR *vp, char const *src)
{
uint8_t *q;
+
VERIFY_VP(vp);
memcpy(&q, &vp->vp_octets, sizeof(q));
vp->vp_strvalue = talloc_steal(vp, src);
vp->type = VT_DATA;
vp->length = talloc_array_length(vp->vp_strvalue) - 1;
+ pairtypeset(vp);
}
/** Copy data into an "string" data type.
VERIFY_VP(vp);
p = talloc_strdup(vp, src);
+
if (!p) return;
memcpy(&q, &vp->vp_strvalue, sizeof(q));
vp->vp_strvalue = p;
vp->type = VT_DATA;
vp->length = talloc_array_length(vp->vp_strvalue) - 1;
+ pairtypeset(vp);
}
+/** Copy data into an "string" data type.
+ *
+ * @param[in,out] vp to update.
+ * @param[in] src data to copy.
+ * @param[in] len of data to copy.
+ */
+void pairstrncpy(VALUE_PAIR *vp, char const *src, size_t len)
+{
+ char *p, *q;
+
+ VERIFY_VP(vp);
+
+ p = talloc_array(vp, char, len + 1);
+ if (!p) return;
+
+ memcpy(p, src, len); /* embdedded \0 safe */
+ p[len] = '\0';
+
+ memcpy(&q, &vp->vp_strvalue, sizeof(q));
+ talloc_free(q);
+
+ vp->vp_strvalue = p;
+ vp->type = VT_DATA;
+ vp->length = len;
+ pairtypeset(vp);
+}
/** Print data into an "string" data type.
*
vp->type = VT_DATA;
vp->length = talloc_array_length(vp->vp_strvalue) - 1;
+ pairtypeset(vp);
}
--- /dev/null
+/*
+ * version.c Validate application and library magic numbers.
+ *
+ * Version: $Id$
+ *
+ * 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
+ *
+ * Copyright 1999-2014 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+static uint64_t libmagic = RADIUSD_MAGIC_NUMBER;
+
+/** Check if the application linking to the library has the correct magic number
+ *
+ * @param magic number as defined by RADIUSD_MAGIC_NUMBER
+ * @returns 0 on success, -1 on prefix mismatch, -2 on version mismatch -3 on commit mismatch.
+ */
+int fr_check_lib_magic(uint64_t magic)
+{
+ if (MAGIC_PREFIX(magic) != MAGIC_PREFIX(libmagic)) {
+ fr_strerror_printf("Application and libfreeradius-radius magic number (prefix) mismatch."
+ " application: %x library: %x",
+ MAGIC_PREFIX(magic), MAGIC_PREFIX(libmagic));
+ return -1;
+ }
+
+ if (MAGIC_VERSION(magic) != MAGIC_VERSION(libmagic)) {
+ fr_strerror_printf("Application and libfreeradius-radius magic number (version) mismatch."
+ " application: %lx library: %lx",
+ (unsigned long) MAGIC_VERSION(magic), (unsigned long) MAGIC_VERSION(libmagic));
+ return -2;
+ }
+
+ if (MAGIC_COMMIT(magic) != MAGIC_COMMIT(libmagic)) {
+ fr_strerror_printf("Application and libfreeradius-radius magic number (commit) mismatch."
+ " application: %lx library: %lx",
+ (unsigned long) MAGIC_COMMIT(magic), (unsigned long) MAGIC_COMMIT(libmagic));
+ return -3;
+ }
+
+ return 0;
+}
*/
case RLM_MODULE_OK:
case RLM_MODULE_UPDATED:
- request->reply->code = PW_ACCOUNTING_RESPONSE;
+ request->reply->code = PW_CODE_ACCOUNTING_RESPONSE;
break;
/*
SUBMAKEFILES := radclient.mk radiusd.mk radsniff.mk radmin.mk radattr.mk \
- radconf2xml.mk radwho.mk radlast.mk radtest.mk radzap.mk checkrad.mk \
+ radwho.mk radlast.mk radtest.mk radzap.mk checkrad.mk \
libfreeradius-server.mk unittest.mk
* Return a short string showing the terminal server, port
* and calling station ID.
*/
-char *auth_name(char *buf, size_t buflen, REQUEST *request, int do_cli)
+char *auth_name(char *buf, size_t buflen, REQUEST *request, bool do_cli)
{
VALUE_PAIR *cli;
VALUE_PAIR *pair;
- int port = 0;
+ uint16_t port = 0;
char const *tls = "";
- if ((cli = pairfind(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY)) == NULL)
- do_cli = 0;
- if ((pair = pairfind(request->packet->vps, PW_NAS_PORT, 0, TAG_ANY)) != NULL)
+ if ((cli = pairfind(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY)) == NULL) {
+ do_cli = false;
+ }
+
+ if ((pair = pairfind(request->packet->vps, PW_NAS_PORT, 0, TAG_ANY)) != NULL) {
port = pair->vp_integer;
+ }
if (request->packet->dst_port == 0) {
if (pairfind(request->packet->vps, PW_FREERADIUS_PROXIED_TO, 0, TAG_ANY)) {
*
* NOTE: NOT the same as the RLM_ values !
*/
-static int rad_check_password(REQUEST *request)
+static int CC_HINT(nonnull) rad_check_password(REQUEST *request)
{
vp_cursor_t cursor;
VALUE_PAIR *auth_type_pair;
int auth_type = -1;
int result;
int auth_type_count = 0;
- result = 0;
/*
* Look for matching check items. We skip the whole lot
* if the authentication type is PW_AUTHTYPE_ACCEPT or
* PW_AUTHTYPE_REJECT.
*/
- paircursor(&cursor, &request->config_items);
- while ((auth_type_pair = pairfindnext(&cursor, PW_AUTH_TYPE, 0, TAG_ANY))) {
+ fr_cursor_init(&cursor, &request->config_items);
+ while ((auth_type_pair = fr_cursor_next_by_num(&cursor, PW_AUTH_TYPE, 0, TAG_ANY))) {
auth_type = auth_type_pair->vp_integer;
auth_type_count++;
if (auth_type < 0) {
if (pairfind(request->config_items, PW_CRYPT_PASSWORD, 0, TAG_ANY) != NULL) {
RWDEBUG2("Please update your configuration, and remove 'Auth-Type = Crypt'");
- RWDEBUG2("Use the PAP module instead.");
+ RWDEBUG2("Use the PAP module instead");
}
else if (pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY) != NULL) {
RWDEBUG2("Please update your configuration, and remove 'Auth-Type = Local'");
- RWDEBUG2("Use the PAP or CHAP modules instead.");
+ RWDEBUG2("Use the PAP or CHAP modules instead");
}
/*
- * The admin hasn't told us how to
- * authenticate the user, so we reject them!
- *
- * This is fail-safe.
- */
+ * The admin hasn't told us how to
+ * authenticate the user, so we reject them!
+ *
+ * This is fail-safe.
+ */
REDEBUG2("No Auth-Type found: rejecting the user via Post-Auth-Type = Reject");
return -2;
case RLM_MODULE_REJECT:
case RLM_MODULE_USERLOCK:
default:
- request->reply->code = PW_AUTHENTICATION_REJECT;
+ request->reply->code = PW_CODE_AUTHENTICATION_REJECT;
result = RLM_MODULE_REJECT;
break;
/*
/*
* If this request got proxied to another server, we need
* to check whether it authenticated the request or not.
+ *
+ * request->proxy gets set only AFTER authorization, so
+ * it's safe to check it here. If it exists, it means
+ * we're doing a second pass through rad_authenticate().
*/
- if (request->proxy_reply) {
- switch (request->proxy_reply->code) {
+ if (request->proxy) {
+ int code = 0;
+
+ if (request->proxy_reply) code = request->proxy_reply->code;
+
+ switch (code) {
/*
* Reply of ACCEPT means accept, thus set Auth-Type
* accordingly.
*/
- case PW_AUTHENTICATION_ACK:
+ case PW_CODE_AUTHENTICATION_ACK:
tmp = radius_paircreate(request,
&request->config_items,
PW_AUTH_TYPE, 0);
* Challenges are punted back to the NAS without any
* further processing.
*/
- case PW_ACCESS_CHALLENGE:
- request->reply->code = PW_ACCESS_CHALLENGE;
+ case PW_CODE_ACCESS_CHALLENGE:
+ request->reply->code = PW_CODE_ACCESS_CHALLENGE;
return RLM_MODULE_OK;
+
/*
* ALL other replies mean reject. (this is fail-safe)
*
* are being rejected, so we minimize the amount of work
* done by the server, by rejecting them here.
*/
- case PW_AUTHENTICATION_REJECT:
+ case PW_CODE_AUTHENTICATION_REJECT:
rad_authlog("Login incorrect (Home Server says so)",
request, 0);
- request->reply->code = PW_AUTHENTICATION_REJECT;
+ request->reply->code = PW_CODE_AUTHENTICATION_REJECT;
return RLM_MODULE_REJECT;
default:
} else {
rad_authlog("Invalid user", request, 0);
}
- request->reply->code = PW_AUTHENTICATION_REJECT;
+ request->reply->code = PW_CODE_AUTHENTICATION_REJECT;
return result;
}
if (!autz_retry) {
* wants to send back.
*/
if (result < 0) {
- RDEBUG2("Failed to authenticate the user.");
- request->reply->code = PW_AUTHENTICATION_REJECT;
+ RDEBUG2("Failed to authenticate the user");
+ request->reply->code = PW_CODE_AUTHENTICATION_REJECT;
if ((module_msg = pairfind(request->packet->vps, PW_MODULE_FAILURE_MESSAGE, 0, TAG_ANY)) != NULL){
char msg[MAX_STRING_LEN+19];
int r, session_type = 0;
char logstr[1024];
char umsg[MAX_STRING_LEN + 1];
- char const *user_msg = NULL;
tmp = pairfind(request->config_items, PW_SESSION_TYPE, 0, TAG_ANY);
if (tmp) {
}
if (!mpp_ok){
if (check_item->vp_integer > 1) {
- snprintf(umsg, sizeof(umsg),
- "\r\nYou are already logged in %d times - access denied\r\n\n",
- (int)check_item->vp_integer);
- user_msg = umsg;
+ snprintf(umsg, sizeof(umsg),
+ "\r\n%s (%d)\r\n\n",
+ main_config.denied_msg,
+ (int)check_item->vp_integer);
} else {
- user_msg = "\r\nYou are already logged in - access denied\r\n\n";
+ snprintf(umsg, sizeof(umsg),
+ "\r\n%s\r\n\n",
+ main_config.denied_msg);
}
- request->reply->code = PW_AUTHENTICATION_REJECT;
+ request->reply->code = PW_CODE_AUTHENTICATION_REJECT;
/*
* They're trying to log in too many times.
*/
pairfree(&request->reply->vps);
pairmake_reply("Reply-Message",
- user_msg, T_OP_SET);
+ umsg, T_OP_SET);
snprintf(logstr, sizeof(logstr), "Multiple logins (max %d) %s",
check_item->vp_integer,
* been set to something. (i.e. Access-Challenge)
*/
if (request->reply->code == 0)
- request->reply->code = PW_AUTHENTICATION_ACK;
+ request->reply->code = PW_CODE_AUTHENTICATION_ACK;
if ((module_msg = pairfind(request->packet->vps, PW_MODULE_SUCCESS_MESSAGE, 0, TAG_ANY)) != NULL){
char msg[MAX_STRING_LEN+12];
* We currently only handle AUTH packets here.
* This could be expanded to handle other packets as well if required.
*/
- rad_assert(request->packet->code == PW_AUTHENTICATION_REQUEST);
+ rad_assert(request->packet->code == PW_CODE_AUTHENTICATION_REQUEST);
result = rad_authenticate(request);
- if (request->reply->code == PW_AUTHENTICATION_REJECT) {
+ if (request->reply->code == PW_CODE_AUTHENTICATION_REJECT) {
pairdelete(&request->config_items, PW_POST_AUTH_TYPE, 0, TAG_ANY);
vp = pairmake_config("Post-Auth-Type", "Reject", T_OP_SET);
if (vp) rad_postauth(request);
}
- if (request->reply->code == PW_AUTHENTICATION_ACK) {
+ if (request->reply->code == PW_CODE_AUTHENTICATION_ACK) {
rad_postauth(request);
}
void cbtls_info(SSL const *s, int where, int ret)
{
char const *str, *state;
- int w;
REQUEST *request = SSL_get_ex_data(s, FR_TLS_EX_INDEX_REQUEST);
- char buffer[1024];
- w = where & ~SSL_ST_MASK;
- if (w & SSL_ST_CONNECT) str=" TLS_connect";
- else if (w & SSL_ST_ACCEPT) str=" TLS_accept";
- else str=" (other)";
+ if ((where & ~SSL_ST_MASK) & SSL_ST_CONNECT) {
+ str="TLS_connect";
+ } else if (((where & ~SSL_ST_MASK)) & SSL_ST_ACCEPT) {
+ str="TLS_accept";
+ } else {
+ str="(other)";
+ }
state = SSL_state_string_long(s);
- state = state ? state : "NULL";
- buffer[0] = '\0';
+ state = state ? state : "<none>";
- if (where & SSL_CB_LOOP) {
- RDEBUG2("%s: %s", str, state);
- } else if (where & SSL_CB_HANDSHAKE_START) {
- RDEBUG2("%s: %s", str, state);
- } else if (where & SSL_CB_HANDSHAKE_DONE) {
+ if ((where & SSL_CB_LOOP) || (where & SSL_CB_HANDSHAKE_START) || (where & SSL_CB_HANDSHAKE_DONE)) {
RDEBUG2("%s: %s", str, state);
- } else if (where & SSL_CB_ALERT) {
- str=(where & SSL_CB_READ)?"read":"write";
-
- snprintf(buffer, sizeof(buffer), "TLS Alert %s:%s:%s",
- str,
- SSL_alert_type_string_long(ret),
- SSL_alert_desc_string_long(ret));
- } else if (where & SSL_CB_EXIT) {
+ return;
+ }
+
+ if (where & SSL_CB_ALERT) {
+ if ((ret & 0xff) == SSL_AD_CLOSE_NOTIFY) return;
+
+ RERROR("TLS Alert %s:%s:%s", (where & SSL_CB_READ) ? "read": "write",
+ SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret));
+ return;
+ }
+
+ if (where & SSL_CB_EXIT) {
if (ret == 0) {
- snprintf(buffer, sizeof(buffer), "%s: failed in %s",
- str, state);
+ RERROR("%s: Failed in %s", str, state);
+ return;
+ }
- } else if (ret < 0) {
+ if (ret < 0) {
if (SSL_want_read(s)) {
- RDEBUG2("%s: Need to read more data: %s",
- str, state);
- } else {
- snprintf(buffer, sizeof(buffer),
- "%s: error in %s", str, state);
+ RDEBUG2("%s: Need to read more data: %s", str, state);
+ return;
}
+ ERROR("tls: %s: Error in %s", str, state);
}
}
-
- if (buffer[0] && request) {
- REDEBUG("SSL says: %s", buffer);
- }
}
/*
state->info.handshake_type = ((unsigned char const *)buf)[0];
state->info.alert_level = 0x00;
state->info.alert_description = 0x00;
+
+#ifdef SSL3_RT_HEARTBEAT
+ } else if (content_type == TLS1_RT_HEARTBEAT) {
+ uint8_t *p = buf;
+
+ if ((len >= 3) && (p[0] == 1)) {
+ size_t payload_len;
+
+ payload_len = (p[1] << 8) | p[2];
+
+ if ((payload_len + 3) > len) {
+ state->invalid_hb_used = true;
+ ERROR("OpenSSL Heartbeat attack detected. Closing connection");
+ return;
+ }
+ }
+#endif
}
tls_session_information(state);
}
# ($login eq $ARGV[3]) ? 1 : 0;
if($login eq $ARGV[3]) {
- return 1;
+ return 1;
}else{
$out=snmpwalk($ARGV[1],$pass,".iso.org.dod.internet.private.enterprises.9.10.19.1.3.1.1.3");
- if($out=~/\"$ARGV[3]\"/){
- return 1;
- }else{
- return 0;
- }
+ if($out=~/\"$ARGV[3]\"/){
+ return 1;
+ }else{
+ return 0;
+ }
}
}
#
sub juniper_e_snmp {
#receives acct_session
- my $temp = $ARGV[4];
- #removes the leading 0s
- my $clean_temp = int $temp;
-
- $out=snmpget($ARGV[1], $cmmty_string, ".1.3.6.1.4.1.4874.2.2.20.1.8.4.1.2.$clean_temp");
- if($out=~/\"$ARGV[3]\"/){
- return 1;
- }else{
- return 0;
- }
+ my $temp = $ARGV[4];
+ #removes the leading 0s
+ my $clean_temp = int $temp;
+
+ $out=snmpget($ARGV[1], $cmmty_string, ".1.3.6.1.4.1.4874.2.2.20.1.8.4.1.2.$clean_temp");
+ if($out=~/\"$ARGV[3]\"/){
+ return 1;
+ }else{
+ return 0;
+ }
}
#
sub multitech_snmp {
my $temp = $ARGV[2] + 1;
- $login = snmpget($ARGV[1], "$cmmty_string", "$msm.2.31.1.1.1.$temp");
- print LOG " user at port S$ARGV[2]: $login\n" if ($debug);
+ $login = snmpget($ARGV[1], "$cmmty_string", "$msm.2.31.1.1.1.$temp");
+ print LOG " user at port S$ARGV[2]: $login\n" if ($debug);
- ($login eq $ARGV[3]) ? 1 : 0;
+ ($login eq $ARGV[3]) ? 1 : 0;
}
#
# Check for known versions
if ($ver eq '1.7.2' || $ver eq '3.0.4') {
if (/^\Q$ARGV[2]\E\s+\S+\s+\S+\s+\S+\s+\Q$trunc\E(\s+|\.\.)/) {
- close FD;
+ close FD;
return 1;
}
next;
}
}
print LOG " User '$ARGV[3]' not found on '$ARGV[1]'.\n" if ($debug);
- 0;
+ 0;
}
#
#
if (snmpget($ARGV[1], "monitor", "$oid") == 0) {
print LOG " Session $ARGV[4] still active on NAS " .
- "$ARGV[1], port $ARGV[2], for user $ARGV[3].\n" if ($debug);
+ "$ARGV[1], port $ARGV[2], for user $ARGV[3].\n" if ($debug);
return 1;
}
0;
my ($login,$password,$oidext);
# Look up community string in naspasswd file.
- ($login, $password) = naspasswd($ARGV[1], 1);
+ ($login, $password) = naspasswd($ARGV[1], 1);
if ($login && $login ne 'SNMP') {
if($debug) {
print LOG
}
else {
$oid = 1257 + 256*int(($args{'tty'}-1) / $hiper_density) +
- (($args{'tty'}-1) % $hiper_density);
+ (($args{'tty'}-1) % $hiper_density);
}
return($oid);
}
$sess->getnext($snmp_var);
} until ($snmp_var->[$SNMP::Varbind::val_f] =~ /$port/) ||
(!($snmp_var->[$SNMP::Varbind::ref_f] =~ /^$port_oid\.(\d+)\.(\d+)$/)) ||
- ($sess->{ErrorNum});
+ ($sess->{ErrorNum});
my $val1 = $snmp_var->[$SNMP::Varbind::ref_f];
# practically this would limit us to a simple only-one user limit for
# this script to work properly.
$t = new Net::Telnet (Timeout => 5,
- Prompt => '//\[.*@.*\] > /');
+ Prompt => '//\[.*@.*\] > /');
# Dont just exit when there is error
$t->errmode('return');
#Send login and password etc.
$t->login(Name => $login,
- Password => $password,
+ Password => $password,
# We must detect if we are logged in from the login banner.
# Because if routeros is with a free license the command
# prompt dont come. Instead it waits us to press "Enter".
- Prompt => '/MikroTik/');
+ Prompt => '/MikroTik/');
# Just be sure that routeros isn't waiting for us to press "Enter"
$t->print("");
} elsif ($ARGV[0] eq 'cvx') {
$ret = &cvx_snmp;
} elsif ($ARGV[0] eq 'juniper') {
- $ret = &juniper_e_snmp;
+ $ret = &juniper_e_snmp;
} elsif ($ARGV[0] eq 'multitech') {
$ret = &multitech_snmp;
} elsif ($ARGV[0] eq 'computone') {
* FIXME: One set of trees for IPv4, and another for IPv6?
*/
rbtree_t *trees[129]; /* for 0..128, inclusive. */
- int min_prefix;
+ uint32_t min_prefix;
};
int i;
if (!clients) clients = root_clients;
+ if (!clients) return; /* Clients may not have been initialised yet */
for (i = 0; i <= 128; i++) {
if (clients->trees[i]) rbtree_free(clients->trees[i]);
return clients;
}
-
-/*
- * Sanity check a client.
- */
-static int client_sane(RADCLIENT *client)
-{
- switch (client->ipaddr.af) {
- case AF_INET:
- if (client->prefix > 32) {
- return 0;
- }
-
- /*
- * Zero out the subnet bits.
- */
- if (client->prefix == 0) {
- memset(&client->ipaddr.ipaddr.ip4addr, 0,
- sizeof(client->ipaddr.ipaddr.ip4addr));
-
- } else if (client->prefix < 32) {
- uint32_t mask = ~0;
-
- mask <<= (32 - client->prefix);
- client->ipaddr.ipaddr.ip4addr.s_addr &= htonl(mask);
- }
- break;
-
- case AF_INET6:
- if (client->prefix > 128) return 0;
-
- if (client->prefix == 0) {
- memset(&client->ipaddr.ipaddr.ip6addr, 0,
- sizeof(client->ipaddr.ipaddr.ip6addr));
-
- } else if (client->prefix < 128) {
- uint32_t mask, *addr;
-
- addr = (uint32_t *) &client->ipaddr.ipaddr.ip6addr;
-
- if ((client->prefix & 0x1f) == 0) {
- mask = 0;
- } else {
- mask = ~ ((uint32_t) 0);
- mask <<= (32 - (client->prefix & 0x1f));
- mask = htonl(mask);
- }
-
- switch (client->prefix >> 5) {
- case 0:
- addr[0] &= mask;
- mask = 0;
- /* FALL-THROUGH */
- case 1:
- addr[1] &= mask;
- mask = 0;
- /* FALL-THROUGH */
- case 2:
- addr[2] &= mask;
- mask = 0;
- /* FALL-THROUGH */
- case 3:
- addr[3] &= mask;
- break;
- }
- }
- break;
-
- default:
- return 0;
- }
-
- return 1;
-}
-
-
/*
* Add a client to the tree.
*/
int client_add(RADCLIENT_LIST *clients, RADCLIENT *client)
{
RADCLIENT *old;
+ char buffer[INET6_ADDRSTRLEN + 3];
if (!client) {
return 0;
}
/*
+ * Hack to fixup wildcard clients
+ */
+ if (is_wildcard(&client->ipaddr)) client->ipaddr.prefix = 0;
+
+ fr_ntop(buffer, sizeof(buffer), &client->ipaddr);
+ DEBUG3("Adding client %s (%s) to prefix tree %i", buffer, client->longname, client->ipaddr.prefix);
+
+ /*
* If "clients" is NULL, it means add to the global list.
*/
if (!clients) {
clients = root_clients;
}
- if ((client->prefix < 0) || (client->prefix > 128)) {
- return 0;
- }
-
- if (!client_sane(client)) return 0;
-
/*
* Create a tree for it.
*/
- if (!clients->trees[client->prefix]) {
- clients->trees[client->prefix] = rbtree_create(client_ipaddr_cmp,
- NULL, 0);
- if (!clients->trees[client->prefix]) {
+ if (!clients->trees[client->ipaddr.prefix]) {
+ clients->trees[client->ipaddr.prefix] = rbtree_create(client_ipaddr_cmp, NULL, 0);
+ if (!clients->trees[client->ipaddr.prefix]) {
return 0;
}
}
/*
* Cannot insert the same client twice.
*/
- old = rbtree_finddata(clients->trees[client->prefix], client);
+ old = rbtree_finddata(clients->trees[client->ipaddr.prefix], client);
if (old) {
/*
* If it's a complete duplicate, then free the new
* one, and return "OK".
*/
if ((fr_ipaddr_cmp(&old->ipaddr, &client->ipaddr) == 0) &&
- (old->prefix == client->prefix) &&
+ (old->ipaddr.prefix == client->ipaddr.prefix) &&
namecmp(longname) && namecmp(secret) &&
namecmp(shortname) && namecmp(nas_type) &&
namecmp(login) && namecmp(password) && namecmp(server) &&
(old->coa_pool == client->coa_pool) &&
#endif
(old->message_authenticator == client->message_authenticator)) {
- WDEBUG("Ignoring duplicate client %s", client->longname);
+ WARN("Ignoring duplicate client %s", client->longname);
client_free(client);
return 1;
}
/*
* Other error adding client: likely is fatal.
*/
- if (!rbtree_insert(clients->trees[client->prefix], client)) {
+ if (!rbtree_insert(clients->trees[client->ipaddr.prefix], client)) {
return 0;
}
if (tree_num) rbtree_insert(tree_num, client);
#endif
- if (client->prefix < clients->min_prefix) {
- clients->min_prefix = client->prefix;
+ if (client->ipaddr.prefix < clients->min_prefix) {
+ clients->min_prefix = client->ipaddr.prefix;
}
(void) talloc_steal(clients, client); /* reparent it */
if (!client->dynamic) return;
- rad_assert((client->prefix >= 0) && (client->prefix <= 128));
+ rad_assert(client->ipaddr.prefix <= 128);
client->dynamic = 2; /* signal to client_free */
#ifdef WITH_STATS
rbtree_deletebydata(tree_num, client);
#endif
- rbtree_deletebydata(clients->trees[client->prefix], client);
+ rbtree_deletebydata(clients->trees[client->ipaddr.prefix], client);
}
#endif
*/
RADCLIENT *client_find(RADCLIENT_LIST const *clients, fr_ipaddr_t const *ipaddr, int proto)
{
- int i, max_prefix;
+ uint32_t i, max_prefix;
RADCLIENT myclient;
if (!clients) clients = root_clients;
for (i = max_prefix; i >= clients->min_prefix; i--) {
void *data;
- myclient.prefix = i;
myclient.ipaddr = *ipaddr;
myclient.proto = proto;
- client_sane(&myclient); /* clean up the ipaddress */
+ fr_ipaddr_mask(&myclient.ipaddr, i);
if (!clients->trees[i]) continue;
data = rbtree_finddata(clients->trees[i], &myclient);
- if (data) {
- return data;
- }
+ if (data) return data;
}
return NULL;
}
-
/*
* Old wrapper for client_find
*/
return client_find(root_clients, ipaddr, IPPROTO_UDP);
}
-static struct in_addr cl_ip4addr;
-static struct in6_addr cl_ip6addr;
-static char *cl_srcipaddr = NULL;
+static fr_ipaddr_t cl_ipaddr;
+static char const *cl_srcipaddr = NULL;
+static uint32_t cl_prefix;
#ifdef WITH_TCP
-static char *hs_proto = NULL;
+static char const *hs_proto = NULL;
#endif
#ifdef WITH_TCP
static CONF_PARSER limit_config[] = {
- { "max_connections", PW_TYPE_INTEGER,
- offsetof(RADCLIENT, limit.max_connections), NULL, "16" },
+ { "max_connections", FR_CONF_OFFSET(PW_TYPE_INTEGER, RADCLIENT, limit.max_connections), "16" },
- { "lifetime", PW_TYPE_INTEGER,
- offsetof(RADCLIENT, limit.lifetime), NULL, "0" },
+ { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, RADCLIENT, limit.lifetime), "0" },
- { "idle_timeout", PW_TYPE_INTEGER,
- offsetof(RADCLIENT, limit.idle_timeout), NULL, "30" },
+ { "idle_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, RADCLIENT, limit.idle_timeout), "30" },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
#endif
static const CONF_PARSER client_config[] = {
- { "ipaddr", PW_TYPE_IPADDR,
- 0, &cl_ip4addr, NULL },
- { "ipv6addr", PW_TYPE_IPV6ADDR,
- 0, &cl_ip6addr, NULL },
- { "netmask", PW_TYPE_INTEGER,
- offsetof(RADCLIENT, prefix), 0, NULL },
-
- { "src_ipaddr", PW_TYPE_STRING_PTR,
- 0, &cl_srcipaddr, NULL },
-
- { "require_message_authenticator", PW_TYPE_BOOLEAN,
- offsetof(RADCLIENT, message_authenticator), 0, "no" },
-
- { "secret", PW_TYPE_STRING_PTR,
- offsetof(RADCLIENT, secret), 0, NULL },
- { "shortname", PW_TYPE_STRING_PTR,
- offsetof(RADCLIENT, shortname), 0, NULL },
- { "nastype", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(RADCLIENT, nas_type), 0, NULL },
- { "nas_type", PW_TYPE_STRING_PTR,
- offsetof(RADCLIENT, nas_type), 0, NULL },
- { "login", PW_TYPE_STRING_PTR,
- offsetof(RADCLIENT, login), 0, NULL },
- { "password", PW_TYPE_STRING_PTR,
- offsetof(RADCLIENT, password), 0, NULL },
- { "virtual_server", PW_TYPE_STRING_PTR,
- offsetof(RADCLIENT, server), 0, NULL },
+ { "ipaddr", FR_CONF_POINTER(PW_TYPE_IP_PREFIX, &cl_ipaddr), NULL },
+ { "ipv4addr", FR_CONF_POINTER(PW_TYPE_IPV4_PREFIX, &cl_ipaddr), NULL },
+ { "ipv6addr", FR_CONF_POINTER(PW_TYPE_IPV6_PREFIX, &cl_ipaddr), NULL },
+ { "netmask", FR_CONF_POINTER(PW_TYPE_INTEGER, &cl_prefix), NULL },
-#ifdef WITH_TCP
- { "proto", PW_TYPE_STRING_PTR,
- 0, &hs_proto, NULL },
+ { "src_ipaddr", FR_CONF_POINTER(PW_TYPE_STRING, &cl_srcipaddr), NULL },
- { "limit", PW_TYPE_SUBSECTION, 0, NULL, (void const *) limit_config },
+ { "require_message_authenticator", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, message_authenticator), "no" },
+
+ { "secret", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, RADCLIENT, secret), NULL },
+ { "shortname", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, shortname), NULL },
+ { "nastype", FR_CONF_OFFSET(PW_TYPE_DEPRECATED | PW_TYPE_STRING, RADCLIENT, nas_type), NULL },
+ { "nas_type", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, nas_type), NULL },
+ { "login", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, login), NULL },
+ { "password", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, password), NULL },
+ { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, server), NULL },
+ { "response_window", FR_CONF_OFFSET(PW_TYPE_TIMEVAL, RADCLIENT, response_window), NULL },
+
+#ifdef WITH_TCP
+ { "proto", FR_CONF_POINTER(PW_TYPE_STRING, &hs_proto), NULL },
+ { "limit", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) limit_config },
#endif
#ifdef WITH_DYNAMIC_CLIENTS
- { "dynamic_clients", PW_TYPE_STRING_PTR,
- offsetof(RADCLIENT, client_server), 0, NULL },
- { "lifetime", PW_TYPE_INTEGER,
- offsetof(RADCLIENT, lifetime), 0, NULL },
- { "rate_limit", PW_TYPE_BOOLEAN,
- offsetof(RADCLIENT, rate_limit), 0, NULL },
+ { "dynamic_clients", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, client_server), NULL },
+ { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, RADCLIENT, lifetime), NULL },
+ { "rate_limit", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, rate_limit), NULL },
#endif
#ifdef WITH_COA
- { "coa_server", PW_TYPE_STRING_PTR,
- offsetof(RADCLIENT, coa_name), 0, NULL },
+ { "coa_server", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, coa_name), NULL },
#endif
{ NULL, -1, 0, NULL, NULL }
}
/*
- * The size is fine.. Let's create the buffer
+ * The size is fine.. Let's create the buffer
*/
c = talloc_zero(cs, RADCLIENT);
c->cs = cs;
- memset(&cl_ip4addr, 0, sizeof(cl_ip4addr));
- memset(&cl_ip6addr, 0, sizeof(cl_ip6addr));
- c->prefix = -1;
-
+ memset(&cl_ipaddr, 0, sizeof(cl_ipaddr));
+ cl_prefix = 256;
if (cf_section_parse(cs, c, client_config) < 0) {
- cf_log_err_cs(cs, "Error parsing client section.");
+ cf_log_err_cs(cs, "Error parsing client section");
error:
client_free(c);
#ifdef WITH_TCP
}
/*
- * Global clients can set servers to use,
- * per-server clients cannot.
+ * Global clients can set servers to use per-server clients cannot.
*/
if (in_server && c->server) {
- cf_log_err_cs(cs,
- "Clients inside of an server section cannot point to a server.");
+ cf_log_err_cs(cs, "Clients inside of an server section cannot point to a server");
goto error;
}
/*
- * No "ipaddr" or "ipv6addr", use old-style
- * "client <ipaddr> {" syntax.
+ * Newer style client definitions with either ipaddr or ipaddr6
+ * config items.
*/
- if (!cf_pair_find(cs, "ipaddr") &&
- !cf_pair_find(cs, "ipv6addr")) {
- char *prefix_ptr;
-
- prefix_ptr = strchr(name2, '/');
+ if (cf_pair_find(cs, "ipaddr") || cf_pair_find(cs, "ipv4addr") || cf_pair_find(cs, "ipv6addr")) {
+ char buffer[128];
/*
- * Look for prefixes.
+ * Sets ipv4/ipv6 address and prefix.
*/
- if (prefix_ptr) {
- c->prefix = atoi(prefix_ptr + 1);
- if ((c->prefix < 0) || (c->prefix > 128)) {
- cf_log_err_cs(cs, "Invalid Prefix value '%s' for IP.", prefix_ptr + 1);
- goto error;
- }
- /* Replace '/' with '\0' */
- *prefix_ptr = '\0';
- }
+ c->ipaddr = cl_ipaddr;
/*
- * Always get the numeric representation of IP
+ * Set the long name to be the result of a reverse lookup on the IP address.
*/
- if (ip_hton(name2, AF_UNSPEC, &c->ipaddr) < 0) {
- cf_log_err_cs(cs,
- "Failed to look up hostname %s: %s",
- name2, fr_strerror());
- goto error;
- }
-
- if (prefix_ptr) *prefix_ptr = '/';
- c->longname = talloc_strdup(c, name2);
-
- if (!c->shortname) c->shortname = talloc_strdup(c, c->longname);
-
- } else {
- char buffer[1024];
+ ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
+ c->longname = talloc_typed_strdup(c, buffer);
/*
- * Figure out which one to use.
+ * Set the short name to the name2.
*/
- if (cf_pair_find(cs, "ipaddr")) {
- c->ipaddr.af = AF_INET;
- c->ipaddr.ipaddr.ip4addr = cl_ip4addr;
+ if (!c->shortname) c->shortname = talloc_typed_strdup(c, name2);
+ /*
+ * No "ipaddr" or "ipv6addr", use old-style "client <ipaddr> {" syntax.
+ */
+ } else {
+ WARN("No 'ipaddr' or 'ipv4addr' or 'ipv6addr' field found in client %s. Please fix your configuration",
+ name2);
+ WARN("Support for old-style clients will be removed in a future release");
- if ((c->prefix < -1) || (c->prefix > 32)) {
- cf_log_err_cs(cs, "Netmask must be between 0 and 32");
+#ifdef WITH_TCP
+ if (cf_pair_find(cs, "proto") != NULL) {
+ cf_log_err_cs(cs, "Cannot use 'proto' inside of old-style client definition");
+ goto error;
+ }
+#endif
+ if (fr_pton(&c->ipaddr, name2, 0, true) < 0) {
+ cf_log_err_cs(cs, "Failed parsing client name \"%s\" as ip address or hostname: %s", name2,
+ fr_strerror());
+ goto error;
+ }
+
+ c->longname = talloc_typed_strdup(c, name2);
+ if (!c->shortname) c->shortname = talloc_typed_strdup(c, c->longname);
+ }
+ /*
+ * Prefix override (this needs to die)
+ */
+ if (cl_prefix != 256) {
+ WARN("'netmask' field found in client %s is deprecated, use CIDR notation instead. "
+ "Please fix your configuration", name2);
+ WARN("Support for 'netmask' will be removed in a future release");
+
+ switch (c->ipaddr.af) {
+ case AF_INET:
+ if (cl_prefix > 32) {
+ cf_log_err_cs(cs, "Invalid IPv4 mask length \"%i\". Should be between 0-32",
+ cl_prefix);
goto error;
}
+ break;
- } else if (cf_pair_find(cs, "ipv6addr")) {
- c->ipaddr.af = AF_INET6;
- c->ipaddr.ipaddr.ip6addr = cl_ip6addr;
-
- if ((c->prefix < -1) || (c->prefix > 128)) {
- cf_log_err_cs(cs,
- "Netmask must be between 0 and 128");
+ case AF_INET6:
+ if (cl_prefix > 128) {
+ cf_log_err_cs(cs, "Invalid IPv6 mask length \"%i\". Should be between 0-128",
+ cl_prefix);
goto error;
}
- } else {
- cf_log_err_cs(cs,
- "No IP address defined for the client");
- goto error;
- }
-
- ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
- c->longname = talloc_strdup(c, buffer);
+ break;
- /*
- * Set the short name to the name2
- */
- if (!c->shortname) c->shortname = talloc_strdup(c, name2);
+ default:
+ rad_assert(0);
+ }
+ fr_ipaddr_mask(&c->ipaddr, cl_prefix);
+ }
- c->proto = IPPROTO_UDP;
- if (hs_proto) {
- if (strcmp(hs_proto, "udp") == 0) {
- hs_proto = NULL;
+ c->proto = IPPROTO_UDP;
+ if (hs_proto) {
+ if (strcmp(hs_proto, "udp") == 0) {
+ hs_proto = NULL;
#ifdef WITH_TCP
- } else if (strcmp(hs_proto, "tcp") == 0) {
- hs_proto = NULL;
- c->proto = IPPROTO_TCP;
-
-#ifdef WITH_TLS
- } else if (strcmp(hs_proto, "tls") == 0) {
- hs_proto = NULL;
- c->proto = IPPROTO_TCP;
- c->tls_required = true;
-
- } else if (strcmp(hs_proto, "radsec") == 0) {
- hs_proto = NULL;
- c->proto = IPPROTO_TCP;
- c->tls_required = true;
-#endif
-
- } else if (strcmp(hs_proto, "*") == 0) {
- hs_proto = NULL;
- c->proto = IPPROTO_IP; /* fake for dual */
+ } else if (strcmp(hs_proto, "tcp") == 0) {
+ hs_proto = NULL;
+ c->proto = IPPROTO_TCP;
+# ifdef WITH_TLS
+ } else if (strcmp(hs_proto, "tls") == 0) {
+ hs_proto = NULL;
+ c->proto = IPPROTO_TCP;
+ c->tls_required = true;
+
+ } else if (strcmp(hs_proto, "radsec") == 0) {
+ hs_proto = NULL;
+ c->proto = IPPROTO_TCP;
+ c->tls_required = true;
+# endif
+ } else if (strcmp(hs_proto, "*") == 0) {
+ hs_proto = NULL;
+ c->proto = IPPROTO_IP; /* fake for dual */
#endif
-
- } else {
- cf_log_err_cs(cs,
- "Unknown proto \"%s\".", hs_proto);
- goto error;
- }
+ } else {
+ cf_log_err_cs(cs, "Unknown proto \"%s\".", hs_proto);
+ goto error;
}
}
*/
if (cl_srcipaddr) {
#ifdef WITH_UDPFROMTO
- if (ip_hton(cl_srcipaddr, c->ipaddr.af, &c->src_ipaddr) < 0) {
- cf_log_err_cs(cs, "Failed parsing src_ipaddr");
- goto error;
+ switch (c->ipaddr.af) {
+ case AF_INET:
+ if (fr_pton4(&c->src_ipaddr, cl_srcipaddr, 0, true, false) < 0) {
+ cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror());
+ goto error;
+ }
+ break;
+
+ case AF_INET6:
+ if (fr_pton6(&c->src_ipaddr, cl_srcipaddr, 0, true, false) < 0) {
+ cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror());
+ goto error;
+ }
+ break;
+ default:
+ rad_assert(0);
}
#else
- WDEBUG("Server not build with udpfromto, ignoring client src_ipaddr");
+ WARN("Server not built with udpfromto, ignoring client src_ipaddr");
#endif
-
cl_srcipaddr = NULL;
}
- if (c->prefix < 0) switch (c->ipaddr.af) {
- case AF_INET:
- c->prefix = 32;
- break;
- case AF_INET6:
- c->prefix = 128;
- break;
- default:
- break;
- }
+ FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, >=, 0, 1000);
+ FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, <=, 60, 0);
+ FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, <=, main_config.max_request_time, 0);
#ifdef WITH_DYNAMIC_CLIENTS
if (c->client_server) {
- c->secret = talloc_strdup(c, "testing123");
+ c->secret = talloc_typed_strdup(c, "testing123");
- if (((c->ipaddr.af == AF_INET) &&
- (c->prefix == 32)) ||
- ((c->ipaddr.af == AF_INET6) &&
- (c->prefix == 128))) {
- cf_log_err_cs(cs,
- "Dynamic clients MUST be a network, not a single IP address.");
+ if (((c->ipaddr.af == AF_INET) && (c->ipaddr.prefix == 32)) ||
+ ((c->ipaddr.af == AF_INET6) && (c->ipaddr.prefix == 128))) {
+ cf_log_err_cs(cs, "Dynamic clients MUST be a network, not a single IP address");
goto error;
}
}
#endif
- if (!c->secret || !*c->secret) {
+ if (!c->secret || (c->secret[0] == '\0')) {
#ifdef WITH_DHCP
char const *value = NULL;
CONF_PAIR *cp = cf_pair_find(cs, "dhcp");
* Secrets aren't needed for DHCP.
*/
if (value && (strcmp(value, "yes") == 0)) return c;
-
#endif
#ifdef WITH_TLS
* "radsec". See RFC 6614.
*/
if (c->tls_required) {
- c->secret = talloc_strdup(cs, "radsec");
+ c->secret = talloc_typed_strdup(cs, "radsec");
} else
#endif
RADCLIENT_LIST *clients_parse_section(CONF_SECTION *section, UNUSED bool tls_required)
#endif
{
- int global = false, in_server = false;
+ bool global = false, in_server = false;
CONF_SECTION *cs;
RADCLIENT *c;
RADCLIENT_LIST *clients;
* non-TLS clients CANNOT use TLS listeners.
*/
if (tls_required != c->tls_required) {
- WARN("Security mismatch (TLS / non-TLS) between client and socket.");
+ cf_log_err_cs(cs, "Client does not have the same TLS configuration as the listener");
+ client_free(c);
+ clients_free(clients);
+ return NULL;
}
#endif
dir = opendir(value);
if (!dir) {
- cf_log_err_cs(cs, "Error reading directory %s: %s", value, strerror(errno));
+ cf_log_err_cs(cs, "Error reading directory %s: %s", value, fr_syserror(errno));
client_free(c);
return NULL;
}
closedir(dir);
}
#endif /* HAVE_DIRENT_H */
-#endif /* WITH_DYNAMIC_CLIENTS */
add_client:
+#endif /* WITH_DYNAMIC_CLIENTS */
if (!client_add(clients, c)) {
cf_log_err_cs(cs,
"Failed to add client %s",
* We overload this structure a lot.
*/
static const CONF_PARSER dynamic_config[] = {
- { "FreeRADIUS-Client-IP-Address", PW_TYPE_IPADDR,
- offsetof(RADCLIENT, ipaddr), 0, NULL },
- { "FreeRADIUS-Client-IPv6-Address", PW_TYPE_IPV6ADDR,
- offsetof(RADCLIENT, ipaddr), 0, NULL },
- { "FreeRADIUS-Client-Src-IP-Address", PW_TYPE_IPADDR,
- offsetof(RADCLIENT, src_ipaddr), 0, NULL },
- { "FreeRADIUS-Client-Src-IPv6-Address", PW_TYPE_IPV6ADDR,
- offsetof(RADCLIENT, src_ipaddr), 0, NULL },
-
- { "FreeRADIUS-Client-Require-MA", PW_TYPE_BOOLEAN,
- offsetof(RADCLIENT, message_authenticator), NULL, NULL },
-
- { "FreeRADIUS-Client-Secret", PW_TYPE_STRING_PTR,
- offsetof(RADCLIENT, secret), 0, "" },
- { "FreeRADIUS-Client-Shortname", PW_TYPE_STRING_PTR,
- offsetof(RADCLIENT, shortname), 0, "" },
- { "FreeRADIUS-Client-NAS-Type", PW_TYPE_STRING_PTR,
- offsetof(RADCLIENT, nas_type), 0, NULL },
- { "FreeRADIUS-Client-Virtual-Server", PW_TYPE_STRING_PTR,
- offsetof(RADCLIENT, server), 0, NULL },
+ { "FreeRADIUS-Client-IP-Address", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, RADCLIENT, ipaddr), NULL },
+ { "FreeRADIUS-Client-IPv6-Address", FR_CONF_OFFSET(PW_TYPE_IPV6_ADDR, RADCLIENT, ipaddr), NULL },
+ { "FreeRADIUS-Client-IP-Prefix", FR_CONF_OFFSET(PW_TYPE_IPV4_PREFIX, RADCLIENT, ipaddr), NULL },
+ { "FreeRADIUS-Client-IPv6-Prefix", FR_CONF_OFFSET(PW_TYPE_IPV6_PREFIX, RADCLIENT, ipaddr), NULL },
+ { "FreeRADIUS-Client-Src-IP-Address", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, RADCLIENT, src_ipaddr), NULL },
+ { "FreeRADIUS-Client-Src-IPv6-Address", FR_CONF_OFFSET(PW_TYPE_IPV6_ADDR, RADCLIENT, src_ipaddr), NULL },
+
+ { "FreeRADIUS-Client-Require-MA", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, message_authenticator), NULL },
+
+ { "FreeRADIUS-Client-Secret", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, secret), "" },
+ { "FreeRADIUS-Client-Shortname", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, shortname), "" },
+ { "FreeRADIUS-Client-NAS-Type", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, nas_type), NULL },
+ { "FreeRADIUS-Client-Virtual-Server", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, server), NULL },
{ NULL, -1, 0, NULL, NULL }
};
* definition.
*/
if (master->server && !c->server) {
- c->server = talloc_strdup(c, master->server);
+ c->server = talloc_typed_strdup(c, master->server);
}
/*
/*
* Initialize the remaining fields.
*/
- c->dynamic = 1;
+ c->dynamic = true;
c->lifetime = master->lifetime;
c->created = time(NULL);
- c->longname = talloc_strdup(c, c->shortname);
+ c->longname = talloc_typed_strdup(c, c->shortname);
DEBUG("- Added client %s with shared secret %s",
ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)),
c->secret);
- return 1;
+ return true;
error:
client_free(c);
- return 0;
+ return false;
}
/** Add a client from a result set (LDAP, SQL, et al)
*
* @param ctx Talloc context.
- * @param identifier Client IP Address / IPv4 subnet / FQDN.
+ * @param identifier Client IP Address / IPv4 subnet / IPv6 subnet / FQDN.
* @param secret Client secret.
* @param shortname Client friendly name.
* @param type NAS-Type.
char const *type, char const *server, bool require_ma)
{
RADCLIENT *c;
- char *id;
- char *prefix;
+ char buffer[128];
rad_assert(identifier);
rad_assert(secret);
c = talloc_zero(ctx, RADCLIENT);
-#ifdef WITH_DYNAMIC_CLIENTS
- c->dynamic = 1;
-#endif
-
- id = talloc_strdup(c, identifier);
-
- /*
- * Look for prefixes
- */
- c->prefix = -1;
- prefix = strchr(id, '/');
- if (prefix) {
- c->prefix = atoi(prefix + 1);
- if ((c->prefix < 0) || (c->prefix > 128)) {
- ERROR("Invalid Prefix value '%s' for IP.", prefix + 1);
- talloc_free(c);
-
- return NULL;
- }
-
- /* Replace '/' with '\0' */
- *prefix = '\0';
- }
-
- /*
- * Always get the numeric representation of IP
- */
- if (ip_hton(id, AF_UNSPEC, &c->ipaddr) < 0) {
- ERROR("Failed to look up hostname %s: %s", id, fr_strerror());
+ if (fr_pton(&c->ipaddr, identifier, 0, true) < 0) {
+ ERROR("%s", fr_strerror());
talloc_free(c);
return NULL;
}
- {
- char buffer[256];
- ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
- c->longname = talloc_strdup(c, buffer);
- }
-
- if (c->prefix < 0) switch (c->ipaddr.af) {
- case AF_INET:
- c->prefix = 32;
- break;
- case AF_INET6:
- c->prefix = 128;
- break;
- default:
- break;
- }
+#ifdef WITH_DYNAMIC_CLIENTS
+ c->dynamic = true;
+#endif
+ ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
+ c->longname = talloc_typed_strdup(c, buffer);
/*
* Other values (secret, shortname, nas_type, virtual_server)
*/
- c->secret = talloc_strdup(c, secret);
-
- if (shortname) {
- c->shortname = talloc_strdup(c, shortname);
- }
-
- if (type) {
- c->nas_type = talloc_strdup(c, type);
- }
-
- if (server) {
- c->server = talloc_strdup(c, server);
- }
-
+ c->secret = talloc_typed_strdup(c, secret);
+ if (shortname) c->shortname = talloc_typed_strdup(c, shortname);
+ if (type) c->nas_type = talloc_typed_strdup(c, type);
+ if (server) c->server = talloc_typed_strdup(c, server);
c->message_authenticator = require_ma;
return c;
}
switch (dynamic_config[i].type) {
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
if (da->attr == PW_FREERADIUS_CLIENT_IP_ADDRESS) {
c->ipaddr.af = AF_INET;
c->ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
- c->prefix = 32;
+ c->ipaddr.prefix = 32;
} else if (da->attr == PW_FREERADIUS_CLIENT_SRC_IP_ADDRESS) {
#ifdef WITH_UDPFROMTO
c->src_ipaddr.af = AF_INET;
c->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
#else
- WDEBUG("Server not build with udpfromto, ignoring FreeRADIUS-Client-Src-IP-Address.");
+ WARN("Server not built with udpfromto, ignoring FreeRADIUS-Client-Src-IP-Address");
#endif
}
break;
- case PW_TYPE_IPV6ADDR:
- if (da->attr == PW_FREERADIUS_CLIENT_SRC_IPV6_ADDRESS) {
+ case PW_TYPE_IPV6_ADDR:
+ if (da->attr == PW_FREERADIUS_CLIENT_IPV6_ADDRESS) {
c->ipaddr.af = AF_INET6;
c->ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
- c->prefix = 128;
+ c->ipaddr.prefix = 128;
} else if (da->attr == PW_FREERADIUS_CLIENT_SRC_IPV6_ADDRESS) {
#ifdef WITH_UDPFROMTO
c->src_ipaddr.af = AF_INET6;
c->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
#else
- WDEBUG("Server not build with udpfromto, ignoring FreeRADIUS-Client-Src-IPv6-Address.");
+ WARN("Server not built with udpfromto, ignoring FreeRADIUS-Client-Src-IPv6-Address");
#endif
}
break;
- case PW_TYPE_STRING_PTR:
+ case PW_TYPE_IPV4_PREFIX:
+ if (da->attr == PW_FREERADIUS_CLIENT_IP_PREFIX) {
+ c->ipaddr.af = AF_INET;
+ memcpy(&c->ipaddr.ipaddr.ip4addr.s_addr, &(vp->vp_ipv4prefix[2]), sizeof(c->ipaddr.ipaddr.ip4addr.s_addr));
+ fr_ipaddr_mask(&c->ipaddr, (vp->vp_ipv4prefix[1] & 0x3f));
+ }
+
+ break;
+
+ case PW_TYPE_IPV6_PREFIX:
+ if (da->attr == PW_FREERADIUS_CLIENT_IPV6_PREFIX) {
+ c->ipaddr.af = AF_INET6;
+ memcpy(&c->ipaddr.ipaddr.ip6addr, &(vp->vp_ipv6prefix[2]), sizeof(c->ipaddr.ipaddr.ip6addr));
+ fr_ipaddr_mask(&c->ipaddr, vp->vp_ipv6prefix[1]);
+ }
+
+ break;
+
+ case PW_TYPE_STRING:
p = (char **) ((char *) c + dynamic_config[i].offset);
if (*p) talloc_free(*p);
if (vp->vp_strvalue[0]) {
- *p = talloc_strdup(c->cs, vp->vp_strvalue);
+ *p = talloc_typed_strdup(c->cs, vp->vp_strvalue);
} else {
*p = NULL;
}
goto error;
}
- if (fr_ipaddr_cmp(&request->packet->src_ipaddr, &c->ipaddr) != 0) {
- char buf2[128];
+ {
+ fr_ipaddr_t addr;
- DEBUG("- Cannot add client %s: IP address %s do not match",
- ip_ntoh(&request->packet->src_ipaddr,
- buffer, sizeof(buffer)),
- ip_ntoh(&c->ipaddr,
- buf2, sizeof(buf2)));
- goto error;
+ /*
+ * Need to apply the same mask as we set for the client
+ * else clients created with FreeRADIUS-Client-IPv6-Prefix
+ * or FreeRADIUS-Client-IPv4-Prefix will fail this check.
+ */
+ addr = request->packet->src_ipaddr;
+ fr_ipaddr_mask(&addr, c->ipaddr.prefix);
+ if (fr_ipaddr_cmp(&addr, &c->ipaddr) != 0) {
+ char buf2[128];
+
+ DEBUG("- Cannot add client %s: IP address %s do not match",
+ ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)),
+ ip_ntoh(&c->ipaddr, buf2, sizeof(buf2)));
+ goto error;
+ }
}
if (!c->secret || !*c->secret) {
return c;
}
#endif
+
--- /dev/null
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 if the
+ * License as published by the Free Software Foundation.
+ *
+ * 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
+ */
+
+/**
+ * $Id$
+ * @file collectd.c
+ * @brief Helper functions to enabled radsniff to talk to collectd
+ *
+ * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+#ifdef HAVE_COLLECTDC_H
+#include <assert.h>
+#include <ctype.h>
+
+#include <collectd/client.h>
+#include <freeradius-devel/radsniff.h>
+
+/** Copy a 64bit unsigned integer into a double
+ *
+ */
+/*
+static void _copy_uint64_to_double(UNUSED rs_t *conf, rs_stats_value_tmpl_t *tmpl)
+{
+ assert(tmpl->src);
+ assert(tmpl->dst);
+
+ *((double *) tmpl->dst) = *((uint64_t *) tmpl->src);
+}
+*/
+
+/*
+static void _copy_uint64_to_uint64(UNUSED rs_t *conf, rs_stats_value_tmpl_t *tmpl)
+{
+ assert(tmpl->src);
+ assert(tmpl->dst);
+
+ *((uint64_t *) tmpl->dst) = *((uint64_t *) tmpl->src);
+}
+*/
+
+static void _copy_double_to_double(UNUSED rs_t *conf, rs_stats_value_tmpl_t *tmpl)
+{
+ assert(tmpl->src);
+ assert(tmpl->dst);
+
+ *((double *) tmpl->dst) = *((double*) tmpl->src);
+}
+
+
+/** Allocates a stats template which describes a single guage/counter
+ *
+ * This is just intended to simplify allocating a fairly complex memory structure
+ * src and dst pointers must be set
+ *
+ * @param ctx Context to allocate collectd struct in.
+ * @param conf Radsniff configuration.
+ * @param plugin_instance usually the type of packet (in our case).
+ * @param type string, the name of a collection of stats e.g. exchange
+ * @param type_instance the name of the counter/guage within the collection e.g. latency.
+ * @param stats structure to derive statistics from.
+ * @param values Value templates used to populate lcc_value_list.
+ * @return a new rs_stats_tmpl_t on success or NULL on failure.
+ */
+static rs_stats_tmpl_t *rs_stats_collectd_init(TALLOC_CTX *ctx, rs_t *conf,
+ char const *plugin_instance,
+ char const *type, char const *type_instance,
+ void *stats,
+ rs_stats_value_tmpl_t const *values)
+{
+ static char hostname[255];
+ static char fqdn[LCC_NAME_LEN];
+
+ size_t len;
+ int i;
+ char *p;
+
+ rs_stats_tmpl_t *tmpl;
+ lcc_value_list_t *value;
+
+ assert(conf);
+ assert(type);
+ assert(type_instance);
+
+ for (len = 0; values[len].src; len++) {} ;
+ assert(len > 0);
+
+ /*
+ * Initialise hostname once so we don't call gethostname every time
+ */
+ if (*fqdn == '\0') {
+ int ret;
+ struct addrinfo hints, *info = NULL;
+
+ if (gethostname(hostname, sizeof(hostname)) < 0) {
+ ERROR("Error getting hostname: %s", fr_syserror(errno));
+
+ return NULL;
+ }
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC; /*either IPV4 or IPV6*/
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_CANONNAME;
+
+ if ((ret = getaddrinfo(hostname, "radius", &hints, &info)) != 0) {
+ ERROR("Error getting hostname: %s", gai_strerror(ret));
+ return NULL;
+ }
+
+ strlcpy(fqdn, info->ai_canonname, sizeof(fqdn));
+
+ freeaddrinfo(info);
+ }
+
+ tmpl = talloc_zero(ctx, rs_stats_tmpl_t);
+ if (!tmpl) {
+ return NULL;
+ }
+
+ tmpl->value_tmpl = talloc_zero_array(tmpl, rs_stats_value_tmpl_t, len);
+ if (!tmpl->value_tmpl) {
+ goto error;
+ }
+
+ tmpl->stats = stats;
+
+ value = talloc_zero(tmpl, lcc_value_list_t);
+ if (!value) {
+ goto error;
+ }
+ tmpl->value = value;
+
+ value->interval = conf->stats.interval;
+ value->values_len = len;
+
+ value->values_types = talloc_zero_array(value, int, len);
+ if (!value->values_types) {
+ goto error;
+ }
+
+ value->values = talloc_zero_array(value, value_t, len);
+ if (!value->values) {
+ goto error;
+ }
+
+ for (i = 0; i < (int) len; i++) {
+ assert(values[i].src);
+ assert(values[i].cb);
+
+ tmpl->value_tmpl[i] = values[i];
+ switch (tmpl->value_tmpl[i].type) {
+ case LCC_TYPE_COUNTER:
+ tmpl->value_tmpl[i].dst = &value->values[i].counter;
+ break;
+
+ case LCC_TYPE_GAUGE:
+ tmpl->value_tmpl[i].dst = &value->values[i].gauge;
+ break;
+
+ case LCC_TYPE_DERIVE:
+ tmpl->value_tmpl[i].dst = &value->values[i].derive;
+ break;
+
+ case LCC_TYPE_ABSOLUTE:
+ tmpl->value_tmpl[i].dst = &value->values[i].absolute;
+ break;
+ default:
+ assert(0);
+ }
+ value->values_types[i] = tmpl->value_tmpl[i].type;
+ }
+
+ /*
+ * These should be OK as is
+ */
+ strlcpy(value->identifier.host, fqdn, sizeof(value->identifier.host));
+
+ /*
+ * Plugin is ASCII only and no '/'
+ */
+ fr_print_string(conf->stats.prefix, strlen(conf->stats.prefix),
+ value->identifier.plugin, sizeof(value->identifier.plugin));
+ for (p = value->identifier.plugin; *p; ++p) {
+ if ((*p == '-') || (*p == '/'))*p = '_';
+ }
+
+ /*
+ * Plugin instance is ASCII only (assuming printable only) and no '/'
+ */
+ fr_print_string(plugin_instance, strlen(plugin_instance),
+ value->identifier.plugin_instance, sizeof(value->identifier.plugin_instance));
+ for (p = value->identifier.plugin_instance; *p; ++p) {
+ if ((*p == '-') || (*p == '/')) *p = '_';
+ }
+
+ /*
+ * Type is ASCII only (assuming printable only) and no '/' or '-'
+ */
+ fr_print_string(type, strlen(type),
+ value->identifier.type, sizeof(value->identifier.type));
+ for (p = value->identifier.type; *p; ++p) {
+ if ((*p == '-') || (*p == '/')) *p = '_';
+ }
+
+ fr_print_string(type_instance, strlen(type_instance),
+ value->identifier.type_instance, sizeof(value->identifier.type_instance));
+ for (p = value->identifier.type_instance; *p; ++p) {
+ if ((*p == '-') || (*p == '/')) *p = '_';
+ }
+
+
+ return tmpl;
+
+ error:
+ talloc_free(tmpl);
+ return NULL;
+}
+
+
+/** Setup stats templates for latency
+ *
+ */
+rs_stats_tmpl_t *rs_stats_collectd_init_latency(TALLOC_CTX *ctx, rs_stats_tmpl_t **out, rs_t *conf,
+ char const *type, rs_latency_t *stats, PW_CODE code)
+{
+ rs_stats_tmpl_t **tmpl, *last;
+ char *p;
+ char buffer[LCC_NAME_LEN];
+ tmpl = out;
+
+ rs_stats_value_tmpl_t rtx[(RS_RETRANSMIT_MAX + 1) + 1 + 1]; // RTX bins + 0 bin + lost + NULL
+ int i;
+
+ /* not static so were thread safe */
+ rs_stats_value_tmpl_t const _packet_count[] = {
+ { &stats->interval.received, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { &stats->interval.linked, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { &stats->interval.unlinked, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { &stats->interval.reused, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { NULL, 0, NULL, NULL }
+ };
+
+ rs_stats_value_tmpl_t const _latency[] = {
+ { &stats->latency_smoothed, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { &stats->interval.latency_average, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { &stats->interval.latency_high, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { &stats->interval.latency_low, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { NULL, 0, NULL, NULL }
+ };
+
+#define INIT_STATS(_ti, _v) do {\
+ strlcpy(buffer, fr_packet_codes[code], sizeof(buffer)); \
+ for (p = buffer; *p; ++p) *p = tolower(*p);\
+ last = *tmpl = rs_stats_collectd_init(ctx, conf, type, _ti, buffer, stats, _v);\
+ if (!*tmpl) {\
+ TALLOC_FREE(*out);\
+ return NULL;\
+ }\
+ tmpl = &(*tmpl)->next;\
+ ctx = *tmpl;\
+ } while (0)
+
+
+ INIT_STATS("radius_count", _packet_count);
+ INIT_STATS("radius_latency", _latency);
+
+ for (i = 0; i < (RS_RETRANSMIT_MAX + 1); i++) {
+ rtx[i].src = &stats->interval.rt[i];
+ rtx[i].type = LCC_TYPE_GAUGE;
+ rtx[i].cb = _copy_double_to_double;
+ rtx[i].dst = NULL;
+ }
+
+ rtx[i].src = &stats->interval.lost;
+ rtx[i].type = LCC_TYPE_GAUGE;
+ rtx[i].cb = _copy_double_to_double;
+ rtx[i].dst = NULL;
+
+ memset(&rtx[++i], 0, sizeof(rs_stats_value_tmpl_t));
+
+ INIT_STATS("radius_rtx", rtx);
+
+ return last;
+}
+
+/** Refresh and send the stats to the collectd server
+ *
+ */
+void rs_stats_collectd_do_stats(rs_t *conf, rs_stats_tmpl_t *tmpls, struct timeval *now)
+{
+ rs_stats_tmpl_t *tmpl = tmpls;
+ char identifier[6 * LCC_NAME_LEN];
+ int i;
+
+ while (tmpl) {
+ /*
+ * Refresh the value of whatever were sending
+ */
+ for (i = 0; i < (int) tmpl->value->values_len; i++) {
+ tmpl->value_tmpl[i].cb(conf, &tmpl->value_tmpl[i]);
+ }
+
+ tmpl->value->time = now->tv_sec;
+
+ lcc_identifier_to_string(conf->stats.handle, identifier, sizeof(identifier), &tmpl->value->identifier);
+
+ if (lcc_putval(conf->stats.handle, tmpl->value) < 0) {
+ char const *error;
+
+ error = lcc_strerror(conf->stats.handle);
+ ERROR("Failed PUTVAL \"%s\" interval=%i %" PRIu64 " : %s",
+ identifier,
+ (int) tmpl->value->interval,
+ (uint64_t) tmpl->value->time,
+ error ? error : "unknown error");
+ }
+
+ tmpl = tmpl->next;
+ }
+}
+
+/** Connect to a collectd server for stats output
+ *
+ * @param[in,out] conf radsniff configuration, we write the generated handle here.
+ * @return 0 on success -1 on failure.
+ */
+int rs_stats_collectd_open(rs_t *conf)
+{
+ assert(conf->stats.collectd);
+
+ /*
+ * Tear down stale connections gracefully.
+ */
+ rs_stats_collectd_close(conf);
+
+ /*
+ * There's no way to get the error from the connection handle
+ * because it's freed on failure, before lcc returns.
+ */
+ if (lcc_connect(conf->stats.collectd, &conf->stats.handle) < 0) {
+ ERROR("Failed opening connection to collectd: %s", fr_syserror(errno));
+ return -1;
+ }
+ DEBUG2("Connected to \"%s\"", conf->stats.collectd);
+
+ assert(conf->stats.handle);
+ return 0;
+}
+
+/** Close connection
+ *
+ * @param[in,out] conf radsniff configuration.
+ * @return 0 on success -1 on failure.
+ */
+int rs_stats_collectd_close(rs_t *conf)
+{
+ assert(conf->stats.collectd);
+
+ int ret = 0;
+
+ if (conf->stats.handle) {
+ ret = lcc_disconnect(conf->stats.handle);
+ conf->stats.handle = NULL;
+ }
+
+ return ret;
+}
+#endif
#ifdef WITH_COMMAND_SOCKET
-#include <freeradius-devel/modpriv.h>
#include <freeradius-devel/parser.h>
#ifdef HAVE_INTTYPES_H
#define COMMAND_BUFFER_SIZE (1024)
typedef struct fr_cs_buffer_t {
- int auth;
- int mode;
- ssize_t offset;
- ssize_t next;
- char buffer[COMMAND_BUFFER_SIZE];
+ int auth;
+ int mode;
+ ssize_t offset;
+ ssize_t next;
+ char buffer[COMMAND_BUFFER_SIZE];
} fr_cs_buffer_t;
#define COMMAND_SOCKET_MAGIC (0xffdeadee)
typedef struct fr_command_socket_t {
- uint32_t magic;
- char *path;
- char *copy; /* <sigh> */
- uid_t uid;
- gid_t gid;
- char *uid_name;
- char *gid_name;
- char *mode_name;
+ uint32_t magic;
+ char const *path;
+ char *copy; /* <sigh> */
+ uid_t uid;
+ gid_t gid;
+ char const *uid_name;
+ char const *gid_name;
+ char const *mode_name;
char user[256];
/*
*/
fr_ipaddr_t src_ipaddr; /* src_port is always 0 */
fr_ipaddr_t dst_ipaddr;
- int dst_port;
+ uint16_t dst_port;
rad_listen_t *inject_listener;
RADCLIENT *inject_client;
} fr_command_socket_t;
static const CONF_PARSER command_config[] = {
- { "socket", PW_TYPE_STRING_PTR,
- offsetof(fr_command_socket_t, path), NULL, "${run_dir}/radiusd.sock"},
- { "uid", PW_TYPE_STRING_PTR,
- offsetof(fr_command_socket_t, uid_name), NULL, NULL},
- { "gid", PW_TYPE_STRING_PTR,
- offsetof(fr_command_socket_t, gid_name), NULL, NULL},
- { "mode", PW_TYPE_STRING_PTR,
- offsetof(fr_command_socket_t, mode_name), NULL, NULL},
-
- { NULL, -1, 0, NULL, NULL } /* end the list */
+ { "socket", FR_CONF_OFFSET(PW_TYPE_STRING, fr_command_socket_t, path), "${run_dir}/radiusd.sock" },
+ { "uid", FR_CONF_OFFSET(PW_TYPE_STRING, fr_command_socket_t, uid_name), NULL },
+ { "gid", FR_CONF_OFFSET(PW_TYPE_STRING, fr_command_socket_t, gid_name), NULL },
+ { "mode", FR_CONF_OFFSET(PW_TYPE_STRING, fr_command_socket_t, mode_name), NULL },
+
+ { NULL, -1, 0, NULL, NULL } /* end the list */
};
static FR_NAME_NUMBER mode_names[] = {
{ NULL, 0 }
};
-
-static ssize_t cprintf(rad_listen_t *listener, char const *fmt, ...)
-#ifdef __GNUC__
- __attribute__ ((format (printf, 2, 3)))
-#endif
-;
+extern const FR_NAME_NUMBER mod_rcode_table[];
#ifndef HAVE_GETPEEREID
static int getpeereid(int s, uid_t *euid, gid_t *egid)
struct stat buf;
if (!path) {
- ERROR("No path provided, was NULL.");
+ ERROR("No path provided, was NULL");
return -1;
}
len = strlen(path);
if (len >= sizeof(salocal.sun_path)) {
- ERROR("Path too long in socket filename.");
+ ERROR("Path too long in socket filename");
return -1;
}
if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
ERROR("Failed creating socket: %s",
- strerror(errno));
+ fr_syserror(errno));
return -1;
}
if (stat(path, &buf) < 0) {
if (errno != ENOENT) {
ERROR("Failed to stat %s: %s",
- path, strerror(errno));
+ path, fr_syserror(errno));
close(sockfd);
return -1;
}
}
if (unlink(path) < 0) {
- ERROR("Failed to delete %s: %s",
- path, strerror(errno));
- close(sockfd);
- return -1;
+ ERROR("Failed to delete %s: %s",
+ path, fr_syserror(errno));
+ close(sockfd);
+ return -1;
}
}
if (bind(sockfd, (struct sockaddr *)&salocal, socklen) < 0) {
ERROR("Failed binding to %s: %s",
- path, strerror(errno));
+ path, fr_syserror(errno));
close(sockfd);
return -1;
}
*/
if (chmod(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0) {
ERROR("Failed setting permissions on %s: %s",
- path, strerror(errno));
+ path, fr_syserror(errno));
close(sockfd);
return -1;
}
if (listen(sockfd, 8) < 0) {
ERROR("Failed listening to %s: %s",
- path, strerror(errno));
+ path, fr_syserror(errno));
close(sockfd);
return -1;
}
if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0) {
ERROR("Failure getting socket flags: %s",
- strerror(errno));
+ fr_syserror(errno));
close(sockfd);
return -1;
}
flags |= O_NONBLOCK;
if( fcntl(sockfd, F_SETFL, flags) < 0) {
ERROR("Failure setting socket flags: %s",
- strerror(errno));
+ fr_syserror(errno));
close(sockfd);
return -1;
}
* This removes the socket from the event fd, so no one
* will be calling us any more.
*/
- event_new_fd(this);
+ radius_update_listener(this);
}
-
-static ssize_t cprintf(rad_listen_t *listener, char const *fmt, ...)
+static ssize_t CC_HINT(format (printf, 2, 3)) cprintf(rad_listen_t *listener, char const *fmt, ...)
{
ssize_t len;
va_list ap;
return 0;
}
- ci = cf_reference_item(mainconfig.config, mainconfig.config, argv[0]);
+ ci = cf_reference_item(main_config.config, main_config.config, argv[0]);
if (!ci) return 0;
if (!cf_item_is_pair(ci)) return 0;
{
int i;
- void const *data;
char const *name1 = cf_section_name1(cs);
char const *name2 = cf_section_name2(cs);
CONF_PARSER const *variables = cf_section_parse_table(cs);
- char buffer[256];
if (name2) {
cprintf(listener, "%.*s%s %s {\n", indent, tabs, name1, name2);
* Print
*/
if (variables) for (i = 0; variables[i].name != NULL; i++) {
+ void const *data;
+ char buffer[256];
+
/*
* No base struct offset, data must be the pointer.
* If data doesn't exist, ignore the entry, there
variables[i].name, *(int const *) data);
break;
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
inet_ntop(AF_INET, data, buffer, sizeof(buffer));
break;
- case PW_TYPE_IPV6ADDR:
+ case PW_TYPE_IPV6_ADDR:
inet_ntop(AF_INET6, data, buffer, sizeof(buffer));
break;
((*(bool const *) data) == false) ? "no" : "yes");
break;
- case PW_TYPE_STRING_PTR:
+ case PW_TYPE_STRING:
case PW_TYPE_FILE_INPUT:
case PW_TYPE_FILE_OUTPUT:
/*
cprintf(listener, "\tthread-unsafe\n");
- if ((mod->type & RLM_TYPE_CHECK_CONFIG_SAFE) != 0)
- cprintf(listener, "\twill-check-config\n");
+ if ((mod->type & RLM_TYPE_CHECK_CONFIG_UNSAFE) != 0)
+ cprintf(listener, "\tno-check-config\n");
if ((mod->type & RLM_TYPE_HUP_SAFE) != 0)
return 1; /* success */
}
+static int command_show_module_status(rad_listen_t *listener, int argc, char *argv[])
+{
+ CONF_SECTION *cs;
+ const module_instance_t *mi;
+
+ if (argc != 1) {
+ cprintf(listener, "ERROR: No module name was given\n");
+ return 0;
+ }
+
+ cs = cf_section_find("modules");
+ if (!cs) return 0;
+
+ mi = find_module_instance(cs, argv[0], 0);
+ if (!mi) {
+ cprintf(listener, "ERROR: No such module \"%s\"\n", argv[0]);
+ return 0;
+ }
+
+ if (!mi->force) {
+ cprintf(listener, "alive\n");
+ } else {
+ cprintf(listener, "%s\n", fr_int2str(mod_rcode_table, mi->code, "<invalid>"));
+ }
+
+
+ return 1; /* success */
+}
+
/*
* Show all loaded modules
static int command_show_home_servers(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
{
int i;
- home_server *home;
+ home_server_t *home;
char const *type, *state, *proto;
char buffer[256];
* The *reported* state changes because
* the internal state machine NEEDS THE
* RIGHT STATE. However, reporting that
- * to the admin will confuse him. So...
- * we lie. Yes, that dress doesn't make
- * you look fat.
+ * to the admin will confuse them.
+ * So... we lie. No, that dress doesn't
+ * make you look fat...
*/
- if ((home->last_packet_recv + home->ping_interval) >= now) {
+ if ((home->last_packet_recv + (int)home->ping_interval) >= now) {
state = "alive";
} else {
state = "unknown";
ip_ntoh(&client->ipaddr, buffer, sizeof(buffer));
if (((client->ipaddr.af == AF_INET) &&
- (client->prefix != 32)) ||
+ (client->ipaddr.prefix != 32)) ||
((client->ipaddr.af == AF_INET6) &&
- (client->prefix != 128))) {
- cprintf(listener, "\t%s/%d\n", buffer, client->prefix);
+ (client->ipaddr.prefix != 128))) {
+ cprintf(listener, "\t%s/%d\n", buffer, client->ipaddr.prefix);
} else {
cprintf(listener, "\t%s\n", buffer);
}
}
-static int command_show_xml(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
-{
- int fd;
- CONF_ITEM *ci;
- FILE *fp;
-
- fd = dup(listener->fd);
- if (fd < 0) return 0;
-
- fp = fdopen(fd, "a");
- if (!fp) {
- cprintf(listener, "ERROR: Can't dup %s\n", strerror(errno));
- return 0;
- }
-
- if (argc == 0) {
- cprintf(listener, "ERROR: <reference> is required\n");
- fclose(fp);
- return 0;
- }
-
- ci = cf_reference_item(mainconfig.config, mainconfig.config, argv[0]);
- if (!ci) {
- cprintf(listener, "ERROR: No such item <reference>\n");
- fclose(fp);
- return 0;
- }
-
- if (cf_item_is_section(ci)) {
- cf_section2xml(fp, cf_itemtosection(ci));
-
- } else if (cf_item_is_pair(ci)) {
- cf_pair2xml(fp, cf_itemtopair(ci));
-
- } else {
- cprintf(listener, "ERROR: No such item <reference>\n");
- fclose(fp);
- return 0;
- }
-
- fclose(fp);
-
- return 1; /* success */
-}
-
static int command_show_version(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
{
cprintf(listener, "%s\n", radiusd_version);
static int command_debug_file(rad_listen_t *listener, int argc, char *argv[])
{
- if (debug_flag && default_log.dest == L_DST_STDOUT) {
+ if (debug_flag && default_log.dst == L_DST_STDOUT) {
cprintf(listener, "ERROR: Cannot redirect debug logs to a file when already in debugging mode.\n");
return -1;
}
extern fr_cond_t *debug_condition;
static int command_debug_condition(UNUSED rad_listen_t *listener, int argc, char *argv[])
{
+ int i;
char const *error;
-
- /*
- * Delete old condition.
- *
- * This is thread-safe because the condition is evaluated
- * in the main server thread, along with code.
- */
- talloc_free(debug_condition);
- debug_condition = NULL;
+ fr_cond_t *new_condition = NULL;
+ char *p, buffer[1024];
/*
* Disable it.
*/
if (argc == 0) {
+ talloc_free(debug_condition);
+ debug_condition = NULL;
return 0;
}
- if (fr_condition_tokenize(NULL, NULL, argv[0], &debug_condition, &error, FR_COND_ONE_PASS) < 0) {
- ERROR("Failed parsing condition '%s': %s", argv[0], error);
+ if (!((argc == 1) &&
+ ((argv[0][0] == '"') || (argv[0][0] == '\'')))) {
+ p = buffer;
+ *p = '\0';
+ for (i = 0; i < argc; i++) {
+ size_t len;
+
+ len = strlcpy(p, argv[i], buffer + sizeof(buffer) - p);
+ p += len;
+ *(p++) = ' ';
+ *p = '\0';
+ }
+
+ } else {
+ /*
+ * Backwards compatibility. De-escape the string.
+ */
+ char quote;
+ char *q;
+
+ p = argv[0];
+ q = buffer;
+
+ quote = *(p++);
+
+ while (true) {
+ if (!*p) {
+ ERROR("Failed parsing condition '%s': Unexpected end of string", argv[0]);
+ return 0;
+ }
+
+ if (*p == quote) {
+ if (p[1]) {
+ ERROR("Failed parsing condition '%s': Unexpected text after end of string", argv[0]);
+ return 0;
+ }
+ *q = '\0';
+ break;
+ }
+
+ if (*p == '\\') {
+ *(q++) = p[1];
+ p += 2;
+ continue;
+ }
+
+ *(q++) = *(p++);
+ }
}
+ if (fr_condition_tokenize(NULL, NULL, buffer, &new_condition, &error, FR_COND_ONE_PASS) < 0) {
+ ERROR("Failed parsing condition '%s': %s", buffer, error);
+ return 0;
+ }
+
+ /*
+ * Delete old condition.
+ *
+ * This is thread-safe because the condition is evaluated
+ * in the main server thread, along with this code.
+ */
+ talloc_free(debug_condition);
+ debug_condition = new_condition;
+
return 0;
}
return NULL;
}
- if (ip_hton(argv[0], AF_UNSPEC, &ipaddr) < 0) {
+ if (ip_hton(&ipaddr, AF_UNSPEC, argv[0], false) < 0) {
cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
fr_strerror());
return NULL;
return client;
}
-
-static int command_show_client_config(rad_listen_t *listener, int argc, char *argv[])
-{
- int fd;
- RADCLIENT *client;
- FILE *fp;
-
- client = get_client(listener, argc, argv);
- if (!client) {
- return 0;
- }
-
- if (!client->cs) return 1;
- fd = dup(listener->fd);
- if (fd < 0) return 0;
-
- fp = fdopen(fd, "a");
- if (!fp) {
- cprintf(listener, "ERROR: Can't dup %s\n", strerror(errno));
- return 0;
- }
-
- cf_section2file(fp, client->cs);
- fclose(fp);
-
- return 1;
-}
-
#ifdef WITH_PROXY
-static home_server *get_home_server(rad_listen_t *listener, int argc,
+static home_server_t *get_home_server(rad_listen_t *listener, int argc,
char *argv[], int *last)
{
- home_server *home;
- int port;
+ home_server_t *home;
+ uint16_t port;
int proto = IPPROTO_UDP;
fr_ipaddr_t ipaddr;
return NULL;
}
- if (ip_hton(argv[0], AF_UNSPEC, &ipaddr) < 0) {
+ if (ip_hton(&ipaddr, AF_UNSPEC, argv[0], false) < 0) {
cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
fr_strerror());
return NULL;
return home;
}
-static int command_show_home_server_config(rad_listen_t *listener, int argc, char *argv[])
-{
- int fd;
- home_server *home;
- FILE *fp;
-
- home = get_home_server(listener, argc, argv, NULL);
- if (!home) {
- return 0;
- }
-
- if (!home->cs) return 1;
- fd = dup(listener->fd);
- if (fd < 0) return 0;
-
- fp = fdopen(fd, "a");
- if (!fp) {
- cprintf(listener, "ERROR: Can't dup %s\n", strerror(errno));
- return 0;
- }
-
- cf_section2file(fp, home->cs);
- fclose(fp);
-
- return 1;
-}
-
static int command_set_home_server_state(rad_listen_t *listener, int argc, char *argv[])
{
int last;
- home_server *home;
+ home_server_t *home;
if (argc < 3) {
cprintf(listener, "ERROR: Must specify <ipaddr> <port> [proto] <state>\n");
static int command_show_home_server_state(rad_listen_t *listener, int argc, char *argv[])
{
- home_server *home;
+ home_server_t *home;
home = get_home_server(listener, argc, argv, NULL);
if (!home) {
vp_cursor_t cursor;
char *output_file;
FILE *fp;
- VALUE_PAIR *vp;
output_file = request_data_reference(request, null_socket_send, 0);
if (!output_file) {
fp = fopen(output_file, "w");
if (!fp) {
ERROR("Failed to send injected file to %s: %s",
- output_file, strerror(errno));
+ output_file, fr_syserror(errno));
return 0;
}
if (request->reply->code != 0) {
char const *what = "reply";
+ VALUE_PAIR *vp;
char buffer[1024];
if (request->reply->code < FR_MAX_PACKET_CODE) {
request->reply->code, request->reply->id);
}
- for (vp = paircursor(&cursor, &request->reply->vps);
+ for (vp = fr_cursor_init(&cursor, &request->reply->vps);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
vp_prints(buffer, sizeof(buffer), vp);
fprintf(fp, "%s\n", buffer);
if (debug_flag) {
char *argv[], int *last)
{
rad_listen_t *sock;
- int port;
+ uint16_t port;
int proto = IPPROTO_UDP;
fr_ipaddr_t ipaddr;
return NULL;
}
- if (ip_hton(argv[0], AF_UNSPEC, &ipaddr) < 0) {
+ if (ip_hton(&ipaddr, AF_UNSPEC, argv[0], false) < 0) {
cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
fr_strerror());
return NULL;
}
sock->src_ipaddr.af = AF_UNSPEC;
- if (ip_hton(argv[0], AF_UNSPEC, &sock->src_ipaddr) < 0) {
+ if (ip_hton(&sock->src_ipaddr, AF_UNSPEC, argv[0], false) < 0) {
cprintf(listener, "ERROR: Failed parsing IP address; %s\n",
fr_strerror());
return 0;
static int command_inject_file(rad_listen_t *listener, int argc, char *argv[])
{
static int inject_id = 0;
- int filedone;
+ int ret;
+ bool filedone;
fr_command_socket_t *sock = listener->data;
rad_listen_t *fake;
RADIUS_PACKET *packet;
fp = fopen(argv[0], "r");
if (!fp ) {
cprintf(listener, "ERROR: Failed opening %s: %s\n",
- argv[0], strerror(errno));
+ argv[0], fr_syserror(errno));
return 0;
}
- vp = readvp2(NULL, fp, &filedone, "");
+ ret = readvp2(&vp, NULL, fp, &filedone);
fclose(fp);
- if (!vp) {
+ if (ret < 0) {
cprintf(listener, "ERROR: Failed reading attributes from %s: %s\n",
argv[0], fr_strerror());
return 0;
packet->id = inject_id++;
if (fake->type == RAD_LISTEN_AUTH) {
- packet->code = PW_AUTHENTICATION_REQUEST;
+ packet->code = PW_CODE_AUTHENTICATION_REQUEST;
fun = rad_authenticate;
} else {
#ifdef WITH_ACCOUNTING
- packet->code = PW_ACCOUNTING_REQUEST;
+ packet->code = PW_CODE_ACCOUNTING_REQUEST;
fun = rad_accounting;
#else
cprintf(listener, "ERROR: This server was built without accounting support.\n");
buffer, sizeof(buffer)),
packet->code, packet->id);
- for (vp = paircursor(&cursor, &packet->vps);
+ for (vp = fr_cursor_init(&cursor, &packet->vps);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
vp_prints(buffer, sizeof(buffer), vp);
DEBUG("\t%s", buffer);
}
- WDEBUG("INJECTION IS LEAKING MEMORY!");
+ WARN("INJECTION IS LEAKING MEMORY!");
}
if (!request_receive(fake, packet, sock->inject_client, fun)) {
* Remember what the output file is, and remember to
* delete the fake listener when done.
*/
- request_data_add(request, null_socket_send, 0, talloc_strdup(NULL, buffer), true);
+ request_data_add(request, null_socket_send, 0, talloc_typed_strdup(NULL, buffer), true);
request_data_add(request, null_socket_send, 1, fake, true);
#endif
{ "methods", FR_READ,
"show module methods <module> - show sections where <module> may be used",
command_show_module_methods, NULL },
+ { "status", FR_READ,
+ "show module status <module> - show the module status",
+ command_show_module_status, NULL },
{ NULL, 0, NULL, NULL, NULL }
};
static fr_command_table_t command_table_show_client[] = {
- { "config", FR_READ,
- "show client config <ipaddr> "
-#ifdef WITH_TCP
- "[proto] "
-#endif
- "- show configuration for given client",
- command_show_client_config, NULL },
{ "list", FR_READ,
"show client list - shows list of global clients",
command_show_clients, NULL },
#ifdef WITH_PROXY
static fr_command_table_t command_table_show_home[] = {
- { "config", FR_READ,
- "show home_server config <ipaddr> <port> [proto] - show configuration for given home server",
- command_show_home_server_config, NULL },
{ "list", FR_READ,
"show home_server list - shows list of home servers",
command_show_home_servers, NULL },
{ "version", FR_READ,
"show version - Prints version of the running server",
command_show_version, NULL },
- { "xml", FR_READ,
- "show xml <reference> - Prints out configuration as XML",
- command_show_xml, NULL },
{ NULL, 0, NULL, NULL, NULL }
};
*/
cf_pair_replace(mi->cs, cp, argv[2]);
- rcode = cf_item_parse(mi->cs, argv[1], variables[i].type,
- data, argv[2]);
+ rcode = cf_item_parse(mi->cs, argv[1], variables[i].type, data, argv[2]);
if (rcode < 0) {
cprintf(listener, "ERROR: Failed to parse value\n");
return 0;
if (strcmp(argv[1], "alive") == 0) {
- mi->dead = false;
+ mi->force = false;
} else if (strcmp(argv[1], "dead") == 0) {
- mi->dead = true;
+ mi->code = RLM_MODULE_FAIL;
+ mi->force = true;
} else {
- cprintf(listener, "ERROR: Unknown status \"%s\"\n", argv[2]);
- return 0;
+ int rcode;
+
+ rcode = fr_str2int(mod_rcode_table, argv[1], -1);
+ if (rcode < 0) {
+ cprintf(listener, "ERROR: Unknown status \"%s\"\n", argv[1]);
+ return 0;
+ }
+
+ mi->code = rcode;
+ mi->force = true;
}
return 1; /* success */
}
data = NULL;
- for (this = mainconfig.listen; this != NULL; this = this->next) {
+ for (this = main_config.listen; this != NULL; this = this->next) {
if (this->type != RAD_LISTEN_DETAIL) continue;
data = this->data;
#ifdef WITH_PROXY
static int command_stats_home_server(rad_listen_t *listener, int argc, char *argv[])
{
- home_server *home;
+ home_server_t *home;
if (argc == 0) {
cprintf(listener, "ERROR: Must specify [auth/acct] OR <ipaddr> <port>\n");
static int command_stats_client(rad_listen_t *listener, int argc, char *argv[])
{
- int auth = true;
+ bool auth = true;
fr_stats_t *stats;
RADCLIENT *client, fake;
static int command_stats_socket(rad_listen_t *listener, int argc, char *argv[])
{
- int auth = true;
+ bool auth = true;
rad_listen_t *sock;
sock = get_socket(listener, argc, argv, NULL);
#endif /* WITH_STATS */
+#ifdef WITH_DYNAMIC_CLIENTS
static int command_add_client_file(rad_listen_t *listener, int argc, char *argv[])
{
RADCLIENT *c;
static int command_del_client(rad_listen_t *listener, int argc, char *argv[])
{
-#ifdef WITH_DYNAMIC_CLIENTS
RADCLIENT *client;
client = get_client(listener, argc, argv);
* structure will stick around for a while. Oh well...
*/
client->lifetime = 1;
-#else
- cprintf(listener, "ERROR: Dynamic clients are not supported.\n");
-#endif
return 1;
}
{ NULL, 0, NULL, NULL, NULL }
};
-
+#endif
#ifdef WITH_PROXY
static fr_command_table_t command_table_set_home[] = {
command_set_module_config, NULL },
{ "status", FR_WRITE,
- "set module status [alive|dead] - set the module to be alive or dead (always return \"fail\")",
+ "set module status <module> [alive|...] - set the module status to be alive (operating normally), or force a particular code (ok,fail, etc.)",
command_set_module_status, NULL },
{ NULL, 0, NULL, NULL, NULL }
#endif
static fr_command_table_t command_table[] = {
+#ifdef WITH_DYNAMIC_CLIENTS
{ "add", FR_WRITE, NULL, NULL, command_table_add },
+#endif
{ "debug", FR_WRITE,
"debug <command> - debugging commands",
NULL, command_table_debug },
+#ifdef WITH_DYNAMIC_CLIENTS
{ "del", FR_WRITE, NULL, NULL, command_table_del },
+#endif
{ "hup", FR_WRITE,
"hup [module] - sends a HUP signal to the server, or optionally to one module",
command_hup, NULL },
sock->magic = COMMAND_SOCKET_MAGIC;
sock->copy = NULL;
- if (sock->path) sock->copy = talloc_strdup(sock, sock->path);
+ if (sock->path) sock->copy = talloc_typed_strdup(sock, sock->path);
#if defined(HAVE_GETPEEREID) || defined (SO_PEERCRED)
if (sock->uid_name) {
pw = getpwnam(sock->uid_name);
if (!pw) {
ERROR("Failed getting uid for %s: %s",
- sock->uid_name, strerror(errno));
+ sock->uid_name, fr_syserror(errno));
return -1;
}
gr = getgrnam(sock->gid_name);
if (!gr) {
ERROR("Failed getting gid for %s: %s",
- sock->gid_name, strerror(errno));
+ sock->gid_name, fr_syserror(errno));
return -1;
}
sock->gid = gr->gr_gid;
fr_suid_up();
if (fchown(this->fd, sock->uid, sock->gid) < 0) {
ERROR("Failed setting ownership of %s: %s",
- sock->path, strerror(errno));
+ sock->path, fr_syserror(errno));
fr_suid_down();
return -1;
}
static int str2argvX(char *str, char **argv, int max_argc)
{
int argc = 0;
- size_t len;
- char buffer[1024];
while (*str) {
if (argc >= max_argc) return argc;
if (!*str) return argc;
+ argv[argc++] = str;
+
if ((*str == '\'') || (*str == '"')) {
- char const *p = str;
- FR_TOKEN token;
+ char quote = *str;
+ char *p = str + 1;
- token = gettoken(&p, buffer, sizeof(buffer));
- if ((token != T_SINGLE_QUOTED_STRING) &&
- (token != T_DOUBLE_QUOTED_STRING)) {
- return -1;
- }
+ while (true) {
+ if (!*p) return -1;
- len = strlen(buffer);
- if (len >= (size_t) (p - str)) {
- return -1;
- }
+ if (*p == quote) {
+ str = p + 1;
+ break;
+ }
- memcpy(str, buffer, len + 1);
- argv[argc] = str;
+ /*
+ * Handle \" and nothing else.
+ */
+ if (*p == '\\') {
+ p += 2;
+ continue;
+ }
- memcpy(&str, &p, sizeof(str));
- } else {
- argv[argc] = str;
+ p++;
+ }
}
- argc++;
while (*str &&
(*str != ' ') &&
}
len = 1;
- rcode = table[i].func(listener,
- argc - 1, argv + 1);
+ table[i].func(listener, argc - 1, argv + 1);
break;
}
}
magic = htonl(0xf7eead15);
if (write(newfd, &magic, 4) < 0) {
ERROR("Failed writing initial data to socket: %s",
- strerror(errno));
+ fr_syserror(errno));
return -1;
}
magic = htonl(1);
}
if (write(newfd, &magic, 4) < 0) {
- ERROR("Failed writing initial data to socket: %s", strerror(errno));
+ ERROR("Failed writing initial data to socket: %s", fr_syserror(errno));
return -1;
}
* FIXME: EINTR, etc.
*/
if (write(newfd, co->buffer, 16) < 0) {
- ERROR("Failed writing version data to socket: %s", strerror(errno));
+ ERROR("Failed writing version data to socket: %s", fr_syserror(errno));
return -1;
}
}
if (errno == EINTR) return 0;
ERROR("Failed reading from control socket; %s",
- strerror(errno));
+ fr_syserror(errno));
goto close_socket;
}
salen = sizeof(src);
- DEBUG2(" ... new connection request on command socket.");
+ DEBUG2(" ... new connection request on command socket");
newfd = accept(listener->fd, (struct sockaddr *) &src, &salen);
if (newfd < 0) {
return 0;
}
- DEBUG2(" ... failed to accept connection.");
+ DEBUG2(" ... failed to accept connection");
return 0;
}
if (getpeereid(newfd, &uid, &gid) < 0) {
ERROR("Failed getting peer credentials for %s: %s",
- sock->path, strerror(errno));
+ sock->path, fr_syserror(errno));
close(newfd);
return 0;
}
/*
* Tell the event loop that we have a new FD
*/
- event_new_fd(this);
+ radius_update_listener(this);
return 0;
}
CONF_ITEM item;
char const *name1;
char const *name2;
+ FR_TOKEN name2_type;
struct conf_item *children;
struct conf_item *tail; /* for speed */
CONF_SECTION *template;
rbtree_t *name2_tree; /* for sections of the same name2 */
rbtree_t *data_tree;
void *base;
- int depth;
+ int depth;
CONF_PARSER const *variables;
};
CONF_SECTION *outercs,
char *output, size_t outsize,
char const *input);
+static CONF_SECTION *cf_template_copy(CONF_SECTION *parent, CONF_SECTION const *template);
/*
* Isolate the scary casts in these tiny provably-safe functions
cp->value_type = value_type;
cp->op = op;
- cp->attr = talloc_strdup(cp, attr);
+ cp->attr = talloc_typed_strdup(cp, attr);
if (!cp->attr) {
error:
talloc_free(cp);
}
if (value) {
- cp->value = talloc_strdup(cp, value);
+ cp->value = talloc_typed_strdup(cp, value);
if (!cp->value) goto error;
}
rad_assert(strcmp(one->name1, two->name1) == 0);
if (!one->name2 && !two->name2) return 0;
- if (!one->name2) return -1;
- if (!two->name2) return +1;
+ if (one->name2 && !two->name2) return -1;
+ if (!one->name2 && two->name2) return +1;
return strcmp(one->name2, two->name2);
}
cs->item.type = CONF_ITEM_SECTION;
cs->item.parent = parent;
- cs->name1 = talloc_strdup(cs, name1);
+ cs->name1 = talloc_typed_strdup(cs, name1);
if (!cs->name1) {
error:
talloc_free(cs);
}
if (name2 && *name2) {
- cs->name2 = talloc_strdup(cs, name2);
+ cs->name2 = talloc_typed_strdup(cs, name2);
if (!cs->name2) goto error;
}
*/
switch (ci->type) {
case CONF_ITEM_PAIR:
- rbtree_insert(cs->pair_tree, ci);
+ if (!rbtree_insert(cs->pair_tree, ci)) {
+ CONF_PAIR *cp = cf_itemtopair(ci);
+
+ if (strcmp(cp->attr, "confdir") == 0) break;
+ if (!cp->value) break; /* module name, "ok", etc. */
+ }
break;
case CONF_ITEM_SECTION: {
CONF_SECTION *cs_new = cf_itemtosection(ci);
+ CONF_SECTION *name1_cs;
if (!cs->section_tree) {
cs->section_tree = rbtree_create(section_cmp, NULL, 0);
}
}
- rbtree_insert(cs->section_tree, cs_new);
+ name1_cs = rbtree_finddata(cs->section_tree, cs_new);
+ if (!name1_cs) {
+ if (!rbtree_insert(cs->section_tree, cs_new)) {
+ ERROR("Failed inserting section into tree");
+ fr_exit_now(1);
+ }
+ break;
+ }
+#if 0
/*
- * Two names: find the named instance.
+ * We'll ignore these checks for
+ * now. Various sections can be
+ * duplicated, such as "listen",
+ * "update", "if", "else", etc.
*/
- {
- CONF_SECTION *old_cs;
+ if (!name1_cs->name2 && !cs_new->name2) {
+ WARN("%s[%d] Duplicate configuration section \"%s { ...}\" %s %d",
+ ci->filename, ci->lineno, cs_new->name1, name1_cs->item.filename, name1_cs->item.lineno);
+ break;
+ }
- /*
- * Find the FIRST
- * CONF_SECTION having
- * the given name1, and
- * create a new tree
- * under it.
- */
- old_cs = rbtree_finddata(cs->section_tree, cs_new);
- if (!old_cs) return; /* this is a bad error! */
+ if ((name1_cs->name2 && cs_new->name2) &&
+ (strcmp(name1_cs->name2, cs_new->name2) == 0)) {
+ WARN("%s[%d] Duplicate configuration section \"%s %s { ...}\"",
+ ci->filename, ci->lineno, cs_new->name1, cs_new->name2);
+ break;
+ }
+#endif
- if (!old_cs->name2_tree) {
- old_cs->name2_tree = rbtree_create(name2_cmp,
- NULL, 0);
- }
- if (old_cs->name2_tree) {
- rbtree_insert(old_cs->name2_tree, cs_new);
+ /*
+ * We already have a section of
+ * this "name1". Add a new
+ * sub-section based on name2.
+ */
+ if (!name1_cs->name2_tree) {
+ name1_cs->name2_tree = rbtree_create(name2_cmp,
+ NULL, 0);
+ if (!name1_cs->name2_tree) {
+ ERROR("Out of memory");
+ fr_exit_now(1);
}
- } /* had a name2 */
+ }
+
+ /*
+ * We don't care if this fails.
+ * If the user tries to create
+ * two sections of the same
+ * name1/name2, the duplicate
+ * section is just silently
+ * ignored.
+ */
+ rbtree_insert(name1_cs->name2_tree, cs_new);
break;
} /* was a section */
}
no_such_item:
- WDEBUG2("No such configuration item %s", ptr);
+ WARN("No such configuration item %s", ptr);
return NULL;
}
/*
* Find the master parent conf section.
- * We can't use mainconfig.config, because we're in the
+ * We can't use main_config.config, because we're in the
* process of re-building it, and it isn't set up yet...
*/
parentcs = cf_top_section(outercs);
ptr = end + 1;
} else if (ci->type == CONF_ITEM_SECTION) {
+ CONF_SECTION *subcs;
+
/*
* Adding an entry again to a
* section is wrong. We don't
ERROR("%s[%d]: Cannot reference different item in same section", cf, *lineno);
return NULL;
}
- cf_item_add(outercs, ci);
- (void) talloc_reference(outercs, ci);
+
+ /*
+ * Copy the section instead of
+ * referencing it.
+ */
+ subcs = cf_template_copy(outercs, cf_itemtosection(ci));
+ if (!subcs) {
+ ERROR("%s[%d]: Failed copying reference %s", cf, *lineno, name);
+ return NULL;
+ }
+
+ subcs->item.filename = ci->filename;
+ subcs->item.lineno = ci->lineno;
+ cf_item_add(outercs, &(subcs->item));
+
ptr = end + 1;
} else {
static char const *parse_spaces = " ";
+/** Validation function for ipaddr conffile types
+ *
+ */
+static inline int fr_item_validate_ipaddr(CONF_SECTION *cs, char const *name, PW_TYPE type, char const *value,
+ fr_ipaddr_t *ipaddr)
+{
+ char ipbuf[128];
+
+ if (strcmp(value, "*") == 0) {
+ cf_log_info(cs, "%.*s\t%s = *", cs->depth, parse_spaces, name);
+ } else if (strspn(value, ".0123456789abdefABCDEF:%[]/") == strlen(value)) {
+ cf_log_info(cs, "%.*s\t%s = %s", cs->depth, parse_spaces, name, value);
+ } else {
+ cf_log_info(cs, "%.*s\t%s = %s IPv%s address [%s]", cs->depth, parse_spaces, name, value,
+ (ipaddr->af == AF_INET ? "4" : " 6"), ip_ntoh(ipaddr, ipbuf, sizeof(ipbuf)));
+ }
+
+ switch (type) {
+ case PW_TYPE_IPV4_ADDR:
+ case PW_TYPE_IPV6_ADDR:
+ case PW_TYPE_IP_ADDR:
+ switch (ipaddr->af) {
+ case AF_INET:
+ if (ipaddr->prefix != 32) {
+ ERROR("Invalid IPv4 mask length \"/%i\". Only \"/32\" permitted for non-prefix types",
+ ipaddr->prefix);
+
+ return -1;
+ }
+ break;
+
+ case AF_INET6:
+ if (ipaddr->prefix != 128) {
+ ERROR("Invalid IPv6 mask length \"/%i\". Only \"/128\" permitted for non-prefix types",
+ ipaddr->prefix);
+
+ return -1;
+ }
+ break;
+
+ default:
+ return -1;
+ }
+ default:
+ return 0;
+ }
+}
/*
* Parses an item (not a CONF_ITEM) into the specified format,
int cf_item_parse(CONF_SECTION *cs, char const *name, int type, void *data, char const *dflt)
{
int rcode;
- bool deprecated, required, attribute;
+ bool deprecated, required, attribute, secret;
char **q;
char const *value;
- fr_ipaddr_t ipaddr;
CONF_PAIR const *cp = NULL;
- char ipbuf[128];
+ fr_ipaddr_t *ipaddr;
+ char buffer[8192];
if (!cs) return -1;
deprecated = (type & PW_TYPE_DEPRECATED);
required = (type & PW_TYPE_REQUIRED);
attribute = (type & PW_TYPE_ATTRIBUTE);
+ secret = (type & PW_TYPE_SECRET);
type &= 0xff; /* normal types are small */
rcode = 0;
if (attribute) {
- required = 1;
+ required = true;
}
cp = cf_pair_find(cs, name);
break;
case PW_TYPE_INTEGER:
- *(int *)data = strtol(value, 0, 0);
- cf_log_info(cs, "%.*s\t%s = %d",
- cs->depth, parse_spaces, name, *(int *)data);
+ {
+ unsigned long v = strtoul(value, 0, 0);
+
+ /*
+ * Restrict integer values to 0-INT32_MAX, this means
+ * it will always be safe to cast them to a signed type
+ * for comparisons, and imposes the same range limit as
+ * before we switched to using an unsigned type to
+ * represent config item integers.
+ */
+ if (v > INT32_MAX) {
+ cf_log_err(&(cs->item), "Invalid value \"%s\" for variable %s, must be between 0-%u", value,
+ name, INT32_MAX);
+ return -1;
+ }
+
+ *(uint32_t *)data = v;
+ cf_log_info(cs, "%.*s\t%s = %u", cs->depth, parse_spaces, name, *(uint32_t *)data);
+ }
break;
- case PW_TYPE_STRING_PTR:
+ case PW_TYPE_SHORT:
+ {
+ unsigned long v = strtoul(value, 0, 0);
+
+ if (v > UINT16_MAX) {
+ cf_log_err(&(cs->item), "Invalid value \"%s\" for variable %s, must be between 0-%u", value,
+ name, UINT16_MAX);
+ return -1;
+ }
+ *(uint16_t *)data = (uint16_t) v;
+ cf_log_info(cs, "%.*s\t%s = %u", cs->depth, parse_spaces, name, *(uint16_t *)data);
+ }
+ break;
+
+ case PW_TYPE_INTEGER64:
+ *(uint64_t *)data = strtoull(value, 0, 0);
+ cf_log_info(cs, "%.*s\t%s = %" PRIu64, cs->depth, parse_spaces, name, *(uint64_t *)data);
+ break;
+
+ case PW_TYPE_SIGNED:
+ *(int32_t *)data = strtol(value, 0, 0);
+ cf_log_info(cs, "%.*s\t%s = %d", cs->depth, parse_spaces, name, *(int32_t *)data);
+ break;
+
+ case PW_TYPE_STRING:
q = (char **) data;
if (*q != NULL) {
talloc_free(*q);
* file was read.
*/
if (value == dflt) {
- char buffer[8192];
-
int lineno = 0;
lineno = cs->item.lineno;
- /*
- * FIXME: sizeof(buffer)?
- */
value = cf_expand_variables("<internal>",
&lineno,
cs, buffer, sizeof(buffer),
}
}
- cf_log_info(cs, "%.*s\t%s = \"%s\"",
- cs->depth, parse_spaces, name, value ? value : "(null)");
- *q = value ? talloc_strdup(cs, value) : NULL;
+ /*
+ * Hide secrets when using "radiusd -X".
+ */
+ if (secret && (debug_flag <= 2)) {
+ cf_log_info(cs, "%.*s\t%s = <<< secret >>>",
+ cs->depth, parse_spaces, name);
+ } else {
+ cf_log_info(cs, "%.*s\t%s = \"%s\"",
+ cs->depth, parse_spaces, name, value ? value : "(null)");
+ }
+ *q = value ? talloc_typed_strdup(cs, value) : NULL;
break;
/*
- * This is the same as PW_TYPE_STRING_PTR,
+ * This is the same as PW_TYPE_STRING,
* except that we also "stat" the file, and
* cache the result.
*/
* file was read.
*/
if ((value == dflt) && cs) {
- char buffer[8192];
-
int lineno = 0;
- /*
- * FIXME: sizeof(buffer)?
- */
value = cf_expand_variables("?",
&lineno,
cs, buffer, sizeof(buffer),
cf_log_info(cs, "%.*s\t%s = \"%s\"",
cs->depth, parse_spaces, name, value);
- *q = value ? talloc_strdup(cs, value) : NULL;
+ *q = value ? talloc_typed_strdup(cs, value) : NULL;
/*
- * And now we "stat" the file.
+ * If the filename exists and we're supposed to
+ * read it, check it.
*/
- if (*q) {
+ if (*q && (type == PW_TYPE_FILE_INPUT)) {
struct stat buf;
- if (stat(*q, &buf) == 0) {
- time_t *mtime = talloc(cs, time_t);
-
- *mtime = buf.st_mtime;
- /* FIXME: error? */
- cf_data_add_internal(cs, *q, mtime, NULL, type);
- /*
- * We were expecting the file to exist...
- */
- } else if (type == PW_TYPE_FILE_INPUT) {
- ERROR("File \"%s\" does not exist", value);
+ if (stat(*q, &buf) < 0) {
+ ERROR("Unable to open file \"%s\": %s",
+ value, fr_syserror(errno));
return -1;
}
-
}
break;
- case PW_TYPE_IPADDR:
- /*
- * Allow '*' as any address
- */
- if (strcmp(value, "*") == 0) {
- *(uint32_t *) data = htonl(INADDR_ANY);
- cf_log_info(cs, "%.*s\t%s = *",
- cs->depth, parse_spaces, name);
- break;
- }
- if (ip_hton(value, AF_INET, &ipaddr) < 0) {
- ERROR("Can't find IP address for host %s", value);
+ case PW_TYPE_IPV4_ADDR:
+ case PW_TYPE_IPV4_PREFIX:
+ ipaddr = data;
+
+ if (fr_pton4(ipaddr, value, 0, true, false) < 0) {
+ ERROR("%s", fr_strerror());
return -1;
}
+ if (fr_item_validate_ipaddr(cs, name, type, value, ipaddr) < 0) return -1;
+ break;
- if (strspn(value, "0123456789.") == strlen(value)) {
- cf_log_info(cs, "%.*s\t%s = %s",
- cs->depth, parse_spaces, name, value);
- } else {
- cf_log_info(cs, "%.*s\t%s = %s IP address [%s]",
- cs->depth, parse_spaces, name, value,
- ip_ntoh(&ipaddr, ipbuf, sizeof(ipbuf)));
+ case PW_TYPE_IPV6_ADDR:
+ case PW_TYPE_IPV6_PREFIX:
+ ipaddr = data;
+
+ if (fr_pton6(ipaddr, value, 0, true, false) < 0) {
+ ERROR("%s", fr_strerror());
+ return -1;
}
- *(uint32_t *) data = ipaddr.ipaddr.ip4addr.s_addr;
+ if (fr_item_validate_ipaddr(cs, name, type, value, ipaddr) < 0) return -1;
break;
- case PW_TYPE_IPV6ADDR:
- if (ip_hton(value, AF_INET6, &ipaddr) < 0) {
- ERROR("Can't find IPv6 address for host %s", value);
+ case PW_TYPE_IP_ADDR:
+ case PW_TYPE_IP_PREFIX:
+ ipaddr = data;
+
+ if (fr_pton(ipaddr, value, 0, true) < 0) {
+ ERROR("%s", fr_strerror());
return -1;
}
- cf_log_info(cs, "%.*s\t%s = %s IPv6 address [%s]",
- cs->depth, parse_spaces, name, value,
- ip_ntoh(&ipaddr, ipbuf, sizeof(ipbuf)));
- memcpy(data, &ipaddr.ipaddr.ip6addr,
- sizeof(ipaddr.ipaddr.ip6addr));
+ if (fr_item_validate_ipaddr(cs, name, type, value, ipaddr) < 0) return -1;
+ break;
+
+ case PW_TYPE_TIMEVAL: {
+ int sec;
+ char *end;
+ struct timeval tv;
+
+ sec = strtoul(value, &end, 10);
+ tv.tv_sec = sec;
+ tv.tv_usec = 0;
+ if (*end == '.') {
+ sec = strlen(end + 1);
+
+ if (sec > 6) {
+ ERROR("Too much precision for timeval");
+ return -1;
+ }
+
+ strcpy(buffer, "000000");
+ memcpy(buffer, end + 1, sec);
+
+ sec = strtoul(buffer, NULL, 10);
+ tv.tv_usec = sec;
+ }
+ cf_log_info(cs, "%.*s\t%s = %d.%06d",
+ cs->depth, parse_spaces, name, (int) tv.tv_sec, (int) tv.tv_usec);
+ memcpy(data, &tv, sizeof(tv));
+ }
break;
default:
if (!subcs) {
subcs = cf_section_alloc(cs, variables[i].name,
NULL);
- cf_item_add(cs, &(subcs->item));
+ if (!subcs) return;
+
subcs->item.filename = cs->item.filename;
subcs->item.lineno = cs->item.lineno;
+ cf_item_add(cs, &(subcs->item));
}
cf_section_parse_init(subcs, base,
continue;
}
- if ((variables[i].type != PW_TYPE_STRING_PTR) &&
+ if ((variables[i].type != PW_TYPE_STRING) &&
(variables[i].type != PW_TYPE_FILE_INPUT) &&
(variables[i].type != PW_TYPE_FILE_OUTPUT)) {
continue;
}
+static CONF_SECTION *cf_template_copy(CONF_SECTION *parent, CONF_SECTION const *template)
+{
+ CONF_ITEM *ci;
+ CONF_SECTION *cs;
+
+ cs = cf_section_alloc(parent, template->name1, template->name2);
+ if (!cs) return NULL;
+
+ for (ci = template->children; ci; ci = ci->next) {
+ if (ci->type == CONF_ITEM_PAIR) {
+ CONF_PAIR *cp1, *cp2;
+
+ cp1 = cf_itemtopair(ci);
+ cp2 = cf_pair_alloc(cs, cp1->attr, cp1->value, cp1->op, cp1->value_type);
+ if (!cp2) return false;
+
+ cp2->item.filename = cp1->item.filename;
+ cp2->item.lineno = cp1->item.lineno;
+
+ cf_item_add(cs, &(cp2->item));
+ continue;
+ }
+
+ if (ci->type == CONF_ITEM_SECTION) {
+ CONF_SECTION *subcs1, *subcs2;
+
+ subcs1 = cf_itemtosection(ci);
+ subcs2 = cf_template_copy(cs, subcs1);
+
+ subcs2->item.filename = subcs1->item.filename;
+ subcs2->item.lineno = subcs1->item.lineno;
+
+ cf_item_add(cs, &(subcs2->item));
+ continue;
+ }
+
+ /* ignore everything else */
+ }
+
+ return cs;
+}
+
+
+/*
+ * Merge the template so everyting else "just works".
+ */
+static bool cf_template_merge(CONF_SECTION *cs, CONF_SECTION const *template)
+{
+ CONF_ITEM *ci;
+
+ if (!cs || !template) return true;
+
+ cs->template = NULL;
+
+ /*
+ * Walk over the template, adding its' entries to the
+ * current section. But only if the entries don't
+ * already exist in the current section.
+ */
+ for (ci = template->children; ci; ci = ci->next) {
+ if (ci->type == CONF_ITEM_PAIR) {
+ CONF_PAIR *cp1, *cp2;
+
+ /*
+ * It exists, don't over-write it.
+ */
+ cp1 = cf_itemtopair(ci);
+ if (cf_pair_find(cs, cp1->attr)) {
+ continue;
+ }
+
+ /*
+ * Create a new pair with all of the data
+ * of the old one.
+ */
+ cp2 = cf_pair_alloc(cs, cp1->attr, cp1->value, cp1->op, cp1->value_type);
+ if (!cp2) return false;
+
+ cp2->item.filename = cp1->item.filename;
+ cp2->item.lineno = cp1->item.lineno;
+
+ cf_item_add(cs, &(cp2->item));
+ continue;
+ }
+
+ if (ci->type == CONF_ITEM_SECTION) {
+ CONF_SECTION *subcs1, *subcs2;
+
+ subcs1 = cf_itemtosection(ci);
+ rad_assert(subcs1 != NULL);
+
+ subcs2 = cf_section_sub_find_name2(cs, subcs1->name1, subcs1->name2);
+ if (subcs2) {
+ /*
+ * sub-sections get merged.
+ */
+ if (!cf_template_merge(subcs2, subcs1)) {
+ return false;
+ }
+ continue;
+ }
+
+ /*
+ * Our section doesn't have a matching
+ * sub-section. Copy it verbatim from
+ * the template.
+ */
+ subcs2 = cf_template_copy(cs, subcs1);
+ if (!subcs2) return false;
+
+ subcs2->item.filename = subcs1->item.filename;
+ subcs2->item.lineno = subcs1->item.lineno;
+
+ cf_item_add(cs, &(subcs2->item));
+ continue;
+ }
+
+ /* ignore everything else */
+ }
+
+ return true;
+}
+
static char const *cf_local_file(char const *base, char const *filename,
char *buffer, size_t bufsize)
{
CONF_SECTION *current)
{
- CONF_SECTION *this, *css;
+ CONF_SECTION *this, *css, *nextcs;
CONF_PAIR *cpn;
char const *ptr, *start;
char const *value;
char buf1[8192];
char buf2[8192];
char buf3[8192];
- int t1, t2, t3;
- int spaces = false;
+ FR_TOKEN t1, t2, t3;
+ bool spaces = false;
char *cbuf = buf;
size_t len;
fr_cond_t *cond = NULL;
*/
for (;;) {
int at_eof;
+ nextcs = NULL;
/*
* Get data, and remember if we are at EOF.
return -1;
}
- t1 = T_BARE_WORD;
ptr += hack;
- t2 = gettoken(&ptr, buf2, sizeof(buf2));
+ t2 = gettoken(&ptr, buf2, sizeof(buf2), true);
switch (t2) {
case T_EOL:
case T_HASH:
return -1;
}
} else {
- t1 = gettoken(&ptr, buf1, sizeof(buf1));
+ t1 = gettoken(&ptr, buf1, sizeof(buf1), true);
}
/*
ERROR("%s[%d]: Too many closing braces",
filename, *lineno);
return -1;
+ }
+ /*
+ * Merge the template into the existing
+ * section. This uses more memory, but
+ * means that templates now work with
+ * sub-sections, etc.
+ */
+ if (!cf_template_merge(this, this->template)) {
+ return -1;
}
+
this = this->item.parent;
if (seen_too_much(filename, *lineno, ptr)) return -1;
continue;
*/
if ((strcasecmp(buf1, "$INCLUDE") == 0) ||
(strcasecmp(buf1, "$-INCLUDE") == 0)) {
- int relative = 1;
+ bool relative = true;
- t2 = getword(&ptr, buf2, sizeof(buf2));
+ t2 = getword(&ptr, buf2, sizeof(buf2), true);
+ if (t2 != T_EOL) {
+ ERROR("%s[%d]: Unexpected text after $INCLUDE",
+ filename, *lineno);
+ return -1;
+ }
- if (buf2[0] == '$') relative = 0;
+ if (buf2[0] == '$') relative = false;
value = cf_expand_variables(filename, lineno, this, buf, sizeof(buf), buf2);
if (!value) return -1;
- if (!FR_DIR_IS_RELATIVE(value)) relative = 0;
+ if (!FR_DIR_IS_RELATIVE(value)) relative = false;
if (relative) {
value = cf_local_file(filename, value, buf3,
if (stat(value, &stat_buf) < 0) {
ERROR("%s[%d]: Failed reading directory %s: %s",
filename, *lineno,
- value, strerror(errno));
+ value, fr_syserror(errno));
return -1;
}
if (!dir) {
ERROR("%s[%d]: Error reading directory %s: %s",
filename, *lineno, value,
- strerror(errno));
+ fr_syserror(errno));
return -1;
}
struct stat statbuf;
if (stat(value, &statbuf) < 0) {
- WDEBUG("Not including file %s: %s", value, strerror(errno));
+ WARN("Not including file %s: %s", value, fr_syserror(errno));
continue;
}
}
if (strcasecmp(buf1, "$template") == 0) {
CONF_ITEM *ci;
CONF_SECTION *parentcs, *templatecs;
- t2 = getword(&ptr, buf2, sizeof(buf2));
+ t2 = getword(&ptr, buf2, sizeof(buf2), true);
+
+ if (t2 != T_EOL) {
+ ERROR("%s[%d]: Unexpected text after $TEMPLATE",
+ filename, *lineno);
+ return -1;
+ }
parentcs = cf_top_section(current);
return -1;
}
+ if (!this) {
+ ERROR("%s[%d]: Internal sanity check error in template reference",
+ filename, *lineno);
+ return -1;
+ }
+
if (this->template) {
ERROR("%s[%d]: Section already has a template",
filename, *lineno);
if (!server) goto invalid_location;
}
- slen = fr_condition_tokenize(this, cf_sectiontoitem(this), ptr, &cond, &error, FR_COND_TWO_PASS);
+ nextcs = cf_section_alloc(this, buf1, ptr);
+ if (!nextcs) {
+ ERROR("%s[%d]: Failed allocating memory for section",
+ filename, *lineno);
+ return -1;
+ }
+ nextcs->item.filename = talloc_strdup(nextcs, filename);
+ nextcs->item.lineno = *lineno;
+
+ slen = fr_condition_tokenize(nextcs, cf_sectiontoitem(nextcs), ptr, &cond, &error, FR_COND_TWO_PASS);
if (p) *p = '{';
if (slen < 0) {
ERROR("%s[%d]: Parse error in condition",
filename, *lineno);
- EDEBUG("%s", start);
- EDEBUG("%.*s^%s", (int) offset, spbuf, error);
+ ERROR("%s", start);
+ ERROR("%.*s^ %s", (int) offset, spbuf, error);
+ talloc_free(nextcs);
free(spbuf);
return -1;
}
if ((size_t) slen >= (sizeof(buf2) - 1)) {
- talloc_free(cond);
- EDEBUG("%s[%d]: Condition is too large after \"%s\"",
+ talloc_free(nextcs);
+ ERROR("%s[%d]: Condition is too large after \"%s\"",
filename, *lineno, buf1);
return -1;
}
ptr += slen;
t2 = T_BARE_WORD;
- if (gettoken(&ptr, buf3, sizeof(buf3)) != T_LCBRACE) {
- talloc_free(cond);
- EDEBUG("%s[%d]: Expected '{'",
+ if (gettoken(&ptr, buf3, sizeof(buf3), true) != T_LCBRACE) {
+ talloc_free(nextcs);
+ ERROR("%s[%d]: Expected '{'",
filename, *lineno);
return -1;
}
+ /*
+ * Swap the condition with trailing stuff for
+ * the final condition.
+ */
+ memcpy(&p, &nextcs->name2, sizeof(nextcs->name2));
+ talloc_free(p);
+ nextcs->name2 = talloc_typed_strdup(nextcs, buf2);
+
goto section_alloc;
}
/*
* Grab the next token.
*/
- t2 = gettoken(&ptr, buf2, sizeof(buf2));
+ t2 = gettoken(&ptr, buf2, sizeof(buf2), true);
switch (t2) {
case T_EOL:
case T_HASH:
case T_OP_EQ:
case T_OP_SET:
- t3 = getstring(&ptr, buf3, sizeof(buf3));
+ t3 = getstring(&ptr, buf3, sizeof(buf3), true);
if (t3 == T_OP_INVALID) {
ERROR("%s[%d]: Parse error: %s",
filename, *lineno,
*/
do_set:
cpn = cf_pair_alloc(this, buf1, value, t2, t3);
- cpn->item.filename = filename;
+ if (!cpn) return -1;
+ cpn->item.filename = talloc_strdup(cpn, filename);
cpn->item.lineno = *lineno;
cf_item_add(this, &(cpn->item));
continue;
case T_BARE_WORD:
case T_DOUBLE_QUOTED_STRING:
case T_SINGLE_QUOTED_STRING:
- t3 = gettoken(&ptr, buf3, sizeof(buf3));
+ t3 = gettoken(&ptr, buf3, sizeof(buf3), true);
if (t3 != T_LCBRACE) {
ERROR("%s[%d]: Expecting section start brace '{' after \"%s %s\"",
filename, *lineno, buf1, buf2);
return -1;
}
- css = cf_section_alloc(this, buf1,
- t2 == T_LCBRACE ? NULL : buf2);
- if (!css) {
- ERROR("%s[%d]: Failed allocating memory for section",
- filename, *lineno);
- return -1;
- }
- cf_item_add(this, &(css->item));
- css->item.filename = filename;
- css->item.lineno = *lineno;
+ if (!cond) {
+ css = cf_section_alloc(this, buf1,
+ t2 == T_LCBRACE ? NULL : buf2);
+ if (!css) {
+ ERROR("%s[%d]: Failed allocating memory for section",
+ filename, *lineno);
+ return -1;
+ }
- if (cond) {
- /*
- * FIXME: talloc_steal cond to css
- * set "ci" in all of "cond" to css
- *
- * <sigh>
- */
+ css->item.filename = talloc_strdup(css, filename);
+ css->item.lineno = *lineno;
+ cf_item_add(this, &(css->item));
+
+ } else {
+ css = nextcs;
+ nextcs = NULL;
+
+ cf_item_add(this, &(css->item));
cf_data_add_internal(css, "if", cond, NULL, false);
cond = NULL; /* eaten by the above line */
}
/*
+ * There may not be a name2
+ */
+ css->name2_type = (t2 == T_LCBRACE) ? T_OP_INVALID : t2;
+
+ /*
* The current section is now the child section.
*/
this = css;
continue;
+ case T_OP_INVALID:
+ ERROR("%s[%d]: Syntax error in '%s': %s",
+ filename, *lineno, ptr, fr_strerror());
+ return -1;
+
default:
ERROR("%s[%d]: Parse error after \"%s\": unexpected token \"%s\"",
filename, *lineno, buf1, fr_int2str(fr_tokens, t2, "<INVALID>"));
fp = fopen(filename, "r");
if (!fp) {
ERROR("Unable to open file \"%s\": %s",
- filename, strerror(errno));
+ filename, fr_syserror(errno));
return -1;
}
return -1;
}
- if (!cs->item.filename) cs->item.filename = filename;
+ if (!cs->item.filename) cs->item.filename = talloc_strdup(cs, filename);
/*
* Read the section. It's OK to have EOF without a
if (p) *p = '\0';
cp->item.filename = "internal";
- cp->item.lineno = 0;
+ cp->item.lineno = -1;
cf_item_add(cs, &(cp->item));
if (cf_file_include(cs, filename) < 0) {
*/
CONF_PAIR *cf_pair_find(CONF_SECTION const *cs, char const *name)
{
- CONF_ITEM *ci;
- CONF_PAIR *cp = NULL;
+ CONF_PAIR *cp, mycp;
- if (!cs) return NULL;
-
- /*
- * Find the name in the tree, for speed.
- */
- if (name) {
- CONF_PAIR mycp;
+ if (!cs || !name) return NULL;
- mycp.attr = name;
- cp = rbtree_finddata(cs->pair_tree, &mycp);
- } else {
- /*
- * Else find the first one that matches
- */
- for (ci = cs->children; ci; ci = ci->next) {
- if (ci->type == CONF_ITEM_PAIR) {
- return cf_itemtopair(ci);
- }
- }
- }
+ mycp.attr = name;
+ cp = rbtree_finddata(cs->pair_tree, &mycp);
+ if (cp) return cp;
- if (cp || !cs->template) return cp;
+ if (!cs->template) return NULL;
- return cf_pair_find(cs->template, name);
+ return rbtree_finddata(cs->template->pair_tree, &mycp);
}
/*
}
/*
- * Copied here for error reporting.
- */
-extern void fr_strerror_printf(char const *, ...);
-
-/*
* Turn a CONF_PAIR into a VALUE_PAIR
* For now, ignore the "value_type" field...
*/
if ((pair->op != T_OP_CMP_FALSE) &&
((pair->value_type == T_DOUBLE_QUOTED_STRING) ||
(pair->value_type == T_BACK_QUOTED_STRING))) {
- VALUE_PAIR *vp;
+ VALUE_PAIR *vp;
vp = pairmake(pair, NULL, pair->attr, NULL, pair->op);
if (!vp) {
}
/** Find a sub-section in a section
+ *
+ * This finds ANY section having the same first name.
+ * The second name is ignored.
*/
CONF_SECTION *cf_section_sub_find(CONF_SECTION const *cs, char const *name)
{
- CONF_ITEM *ci;
+ CONF_SECTION mycs;
- if (!name) return NULL; /* can't find an un-named section */
+ if (!cs || !name) return NULL; /* can't find an un-named section */
/*
- * Do the fast lookup if possible.
+ * No sub-sections have been defined, so none exist.
*/
- if (cs->section_tree) {
- CONF_SECTION mycs;
-
- mycs.name1 = name;
- mycs.name2 = NULL;
- return rbtree_finddata(cs->section_tree, &mycs);
- }
-
- for (ci = cs->children; ci; ci = ci->next) {
- if (ci->type != CONF_ITEM_SECTION)
- continue;
- if (strcmp(cf_itemtosection(ci)->name1, name) == 0)
- break;
- }
-
- return cf_itemtosection(ci);
+ if (!cs->section_tree) return NULL;
+ mycs.name1 = name;
+ mycs.name2 = NULL;
+ return rbtree_finddata(cs->section_tree, &mycs);
}
CONF_ITEM *ci;
if (!cs) cs = root_config;
+ if (!cs) return NULL;
- if (name1 && (cs->section_tree)) {
+ if (name1) {
CONF_SECTION mycs, *master_cs;
+ if (!cs->section_tree) return NULL;
+
mycs.name1 = name1;
mycs.name2 = name2;
master_cs = rbtree_finddata(cs->section_tree, &mycs);
- if (master_cs) {
- return rbtree_finddata(master_cs->name2_tree, &mycs);
+ if (!master_cs) return NULL;
+
+ /*
+ * Look it up in the name2 tree. If it's there,
+ * return it.
+ */
+ if (master_cs->name2_tree) {
+ CONF_SECTION *subcs;
+
+ subcs = rbtree_finddata(master_cs->name2_tree, &mycs);
+ if (subcs) return subcs;
+ }
+
+ /*
+ * We don't insert ourselves into the name2 tree.
+ * So if there's nothing in the name2 tree, maybe
+ * *we* are the answer.
+ */
+ if (!master_cs->name2 && name2) return NULL;
+ if (master_cs->name2 && !name2) return NULL;
+ if (!master_cs->name2 && !name2) return master_cs;
+
+ if (strcmp(master_cs->name2, name2) == 0) {
+ return master_cs;
}
+
+ return NULL;
}
/*
continue;
subcs = cf_itemtosection(ci);
- if (!name1) {
- if (!subcs->name2) {
- if (strcmp(subcs->name1, name2) == 0) break;
- } else {
- if (strcmp(subcs->name2, name2) == 0) break;
- }
- continue; /* don't do the string comparisons below */
+ if (!subcs->name2) {
+ if (strcmp(subcs->name1, name2) == 0) break;
+ } else {
+ if (strcmp(subcs->name2, name2) == 0) break;
}
-
- if ((strcmp(subcs->name1, name1) == 0) &&
- (subcs->name2 != NULL) &&
- (strcmp(subcs->name2, name2) == 0))
- break;
}
return cf_itemtosection(ci);
cd->item.type = CONF_ITEM_DATA;
cd->item.parent = parent;
- cd->name = talloc_strdup(cd, name);
- if (!cd) {
+ cd->name = talloc_typed_strdup(cd, name);
+ if (!cd->name) {
talloc_free(cd);
return NULL;
}
return cf_data_add_internal(cs, name, data, data_free, 0);
}
-#if 0
-/*
- * Copy CONF_DATA from src to dst
- */
-static void cf_section_copy_data(CONF_SECTION *s, CONF_SECTION *d)
-{
-
- CONF_ITEM *cd, *next, **last;
-
- /*
- * Don't check if s->data_tree is NULL. It's child
- * sections may have data, even if this section doesn't.
- */
-
- rad_assert(d->data_tree == NULL);
- d->data_tree = s->data_tree;
- s->data_tree = NULL;
-
- /*
- * Walk through src, moving CONF_ITEM_DATA
- * to dst, by hand.
- */
- last = &(s->children);
- for (cd = s->children; cd != NULL; cd = next) {
- next = cd->next;
-
- /*
- * Recursively copy data from child sections.
- */
- if (cd->type == CONF_ITEM_SECTION) {
- CONF_SECTION *s1, *d1;
-
- s1 = cf_itemtosection(cd);
- d1 = cf_section_sub_find_name2(d, s1->name1, s1->name2);
- if (d1) {
- cf_section_copy_data(s1, d1);
- }
- last = &(cd->next);
- continue;
- }
-
- /*
- * Not conf data, remember last ptr.
- */
- if (cd->type != CONF_ITEM_DATA) {
- last = &(cd->next);
- continue;
- }
-
- /*
- * Remove it from the src list
- */
- *last = cd->next;
- cd->next = NULL;
-
- /*
- * Add it to the dst list
- */
- if (!d->children) {
- rad_assert(d->tail == NULL);
- d->children = cd;
- } else {
- rad_assert(d->tail != NULL);
- d->tail->next = cd;
- }
- d->tail = cd;
- }
-}
-
-/*
- * For a CONF_DATA element, stat the filename, if necessary.
- */
-static int filename_stat(UNUSED void *context, void *data)
-{
- struct stat buf;
- CONF_DATA *cd = data;
-
- if (cd->flag != PW_TYPE_FILE_INPUT) return 0;
-
- if (stat(cd->name, &buf) < 0) return -1;
-
- if (buf.st_mtime != *(time_t *) cd->data) return -1;
-
- return 0;
-}
-
-
-/*
- * Compare two CONF_SECTIONS. The items MUST be in the same
- * order.
- */
-static int cf_section_cmp(CONF_SECTION *a, CONF_SECTION *b)
-{
- CONF_ITEM *ca = a->children;
- CONF_ITEM *cb = b->children;
-
- while (1) {
- CONF_PAIR *pa, *pb;
-
- /*
- * Done. Stop.
- */
- if (!ca && !cb) break;
-
- /*
- * Skip CONF_DATA.
- */
- if (ca && ca->type == CONF_ITEM_DATA) {
- ca = ca->next;
- continue;
- }
- if (cb && cb->type == CONF_ITEM_DATA) {
- cb = cb->next;
- continue;
- }
-
- /*
- * One is smaller than the other. Exit.
- */
- if (!ca || !cb) return 0;
-
- if (ca->type != cb->type) return 0;
-
- /*
- * Deal with subsections.
- */
- if (ca->type == CONF_ITEM_SECTION) {
- CONF_SECTION *sa = cf_itemtosection(ca);
- CONF_SECTION *sb = cf_itemtosection(cb);
-
- if (!cf_section_cmp(sa, sb)) return 0;
- goto next;
- }
-
- rad_assert(ca->type == CONF_ITEM_PAIR);
-
- pa = cf_itemtopair(ca);
- pb = cf_itemtopair(cb);
-
- /*
- * Different attr and/or value, Exit.
- */
- if ((strcmp(pa->attr, pb->attr) != 0) ||
- (strcmp(pa->value, pb->value) != 0)) return 0;
-
-
- /*
- * And go to the next element.
- */
- next:
- ca = ca->next;
- cb = cb->next;
- }
-
- /*
- * Walk over the CONF_DATA, stat'ing PW_TYPE_FILE_INPUT.
- */
- if (a->data_tree &&
- (rbtree_walk(a->data_tree, InOrder, filename_stat, NULL) != 0)) {
- return 0;
- }
-
- /*
- * They must be the same, say so.
- */
- return 1;
-}
-
-
-/*
- * Migrate CONF_DATA from one section to another.
- */
-int cf_section_migrate(CONF_SECTION *dst, CONF_SECTION *src)
-{
- CONF_ITEM *ci;
- CONF_SECTION *s, *d;
-
- for (ci = src->children; ci != NULL; ci = ci->next) {
- if (ci->type != CONF_ITEM_SECTION)
- continue;
-
- s = cf_itemtosection(ci);
- d = cf_section_sub_find_name2(dst, s->name1, s->name2);
-
- if (!d) continue; /* not in new one, don't migrate it */
-
- /*
- * A section of the same name is in BOTH src & dst,
- * compare the CONF_PAIR's. If they're all the same,
- * then copy the CONF_DATA from one to the other.
- */
- if (cf_section_cmp(s, d)) {
- cf_section_copy_data(s, d);
- }
- }
-
- return 1; /* rcode means anything? */
-}
-#endif
-
-int cf_section_template(CONF_SECTION *cs, CONF_SECTION *template)
-{
- if (!cs || !template || cs->template || template->template) return -1;
-
- cs->template = template;
-
- return 0;
-}
-
-
/*
* This is here to make the rest of the code easier to read. It
* ties conffile.c to log.c, but it means we don't have to
return cs->variables;
}
-#if 0
/*
- * JMG dump_config tries to dump the config structure in a readable format
- *
-*/
-
-static int dump_config_section(CONF_SECTION const *cs, int indent)
-{
- CONF_SECTION *scs;
- CONF_PAIR *cp;
- CONF_ITEM *ci;
-
- /* The DEBUG macro doesn't let me
- * for(i=0;i<indent;++i) debugputchar('\t');
- * so I had to get creative. --Pac. */
-
- for (ci = cs->children; ci; ci = ci->next) {
- switch (ci->type) {
- case CONF_ITEM_PAIR:
- cp=cf_itemtopair(ci);
- DEBUG("%.*s%s = %s",
- indent, "\t\t\t\t\t\t\t\t\t\t\t",
- cp->attr, cp->value);
- break;
-
- case CONF_ITEM_SECTION:
- scs=cf_itemtosection(ci);
- DEBUG("%.*s%s %s%s{",
- indent, "\t\t\t\t\t\t\t\t\t\t\t",
- scs->name1,
- scs->name2 ? scs->name2 : "",
- scs->name2 ? " " : "");
- dump_config_section(scs, indent+1);
- DEBUG("%.*s}",
- indent, "\t\t\t\t\t\t\t\t\t\t\t");
- break;
-
- default: /* FIXME: Do more! */
- break;
- }
- }
-
- return 0;
-}
-
-int dump_config(CONF_SECTION *cs)
-{
- return dump_config_section(cs, 0);
-}
-#endif
-
-static char const *cf_pair_print_value(CONF_PAIR const *cp,
- char *buffer, size_t buflen)
-{
- char *p;
-
- if (!cp->value) return "";
-
- switch (cp->value_type) {
- default:
- case T_BARE_WORD:
- snprintf(buffer, buflen, "%s", cp->value);
- break;
-
- case T_SINGLE_QUOTED_STRING:
- snprintf(buffer, buflen, "'%s'", cp->value);
- break;
-
- case T_DOUBLE_QUOTED_STRING:
- buffer[0] = '"';
- fr_print_string(cp->value, strlen(cp->value),
- buffer + 1, buflen - 3);
- p = buffer + strlen(buffer); /* yuck... */
- p[0] = '"';
- p[1] = '\0';
- break;
- }
-
- return buffer;
-}
-
-
-int cf_pair2xml(FILE *fp, CONF_PAIR const *cp)
-{
- fprintf(fp, "<%s>", cp->attr);
- if (cp->value) {
- char buffer[2048];
-
- char *p = buffer;
- char const *q = cp->value;
-
- while (*q && (p < (buffer + sizeof(buffer) - 1))) {
- if (q[0] == '&') {
- memcpy(p, "&", 4);
- p += 5;
-
- } else if (q[0] == '<') {
- memcpy(p, "<", 4);
- p += 4;
-
- } else if (q[0] == '>') {
- memcpy(p, ">", 4);
- p += 4;
-
- } else {
- *(p++) = *q;
- }
- q++;
- }
-
- *p = '\0';
- fprintf(fp, "%s", buffer);
- }
-
- fprintf(fp, "</%s>\n", cp->attr);
-
- return 1;
-}
-
-int cf_section2xml(FILE *fp, CONF_SECTION const *cs)
-{
- CONF_ITEM *ci, *next;
-
- /*
- * Section header
- */
- fprintf(fp, "<%s>\n", cs->name1);
- if (cs->name2) {
- fprintf(fp, "<_name2>%s</_name2>\n", cs->name2);
- }
-
- /*
- * Loop over contents.
- */
- for (ci = cs->children; ci; ci = next) {
- next = ci->next;
-
- switch (ci->type) {
- case CONF_ITEM_PAIR:
- if (!cf_pair2xml(fp, (CONF_PAIR *) ci)) return 0;
- break;
-
- case CONF_ITEM_SECTION:
- if (!cf_section2xml(fp, (CONF_SECTION *) ci)) return 0;
- break;
-
- default: /* should really be an error. */
- break;
-
- }
- }
-
- fprintf(fp, "</%s>\n", cs->name1);
-
- return 1; /* success */
-}
-
-int cf_pair2file(FILE *fp, CONF_PAIR const *cp)
-{
- char buffer[2048];
-
- fprintf(fp, "\t%s = %s\n", cp->attr,
- cf_pair_print_value(cp, buffer, sizeof(buffer)));
-
- return 1;
-}
-
-int cf_section2file(FILE *fp, CONF_SECTION const *cs)
+ * For "switch" and "case" statements.
+ */
+FR_TOKEN cf_section_name2_type(CONF_SECTION const *cs)
{
- CONF_ITEM const *ci, *next;
-
- /*
- * Section header
- */
- if (!cs->name2) {
- fprintf(fp, "%s {\n", cs->name1);
- } else {
- fprintf(fp, "%s %s {\n",
- cs->name1, cs->name2);
- }
-
- /*
- * Loop over contents.
- */
- for (ci = cs->children; ci; ci = next) {
- next = ci->next;
-
- switch (ci->type) {
- case CONF_ITEM_PAIR:
- if (!cf_pair2file(fp, (CONF_PAIR const *) ci)) return 0;
- break;
-
- case CONF_ITEM_SECTION:
- if (!cf_section2file(fp, (CONF_SECTION const *) ci)) return 0;
- break;
-
- default: /* should really be an error. */
- break;
-
- }
- }
-
- fprintf(fp, "}\n");
+ if (!cs) return T_OP_INVALID;
- return 1; /* success */
+ return cs->name2_type;
}
static int fr_connection_pool_check(fr_connection_pool_t *pool);
+extern bool check_config;
+
+#ifndef NDEBUG
+#ifdef HAVE_PTHREAD_H
+/* #define PTHREAD_DEBUG (1) */
+#endif
+#endif
+
/** An individual connection within the connection pool
*
* Defines connection counters, timestamps, and holds a pointer to the
time_t last_used; //!< Last time the connection was
//!< reserved.
- uint64_t num_uses; //!< Number of times the connection
+ uint32_t num_uses; //!< Number of times the connection
//!< has been reserved.
- int in_use; //!< Whether the connection is currently
- //!< reserved.
uint64_t number; //!< Unique ID assigned when the
//!< connection is created, these will
//!< monotonically increase over the
//!< lifetime of the connection pool.
void *connection; //!< Pointer to whatever the module
//!< uses for a connection handle.
+ bool in_use; //!< Whether the connection is currently
+ //!< reserved.
+#ifdef PTHREAD_DEBUG
+ pthread_t pthread_id; //!< When 'in_use == true'
+#endif
};
/** A connection pool
* @see fr_connection
*/
struct fr_connection_pool_t {
- int start; //!< Number of initial connections
- int min; //!< Minimum number of concurrent
+ uint32_t start; //!< Number of initial connections
+ uint32_t min; //!< Minimum number of concurrent
//!< connections to keep open.
- int max; //!< Maximum number of concurrent
+ uint32_t max; //!< Maximum number of concurrent
//!< connections to allow.
- int spare; //!< Number of spare connections to try
- //!< and maintain.
- int cleanup_delay; //!< How long a connection can go unused
- //!< for before it's closed
- //!< (0 is infinite).
+ uint32_t spare; //!< Number of spare connections to try
+ uint32_t retry_delay; //!< seconds to delay re-open
+ //!< after a failed open.
+ uint32_t cleanup_interval; //!< Initial timer for how
+ //!< often we sweep the pool
+ //!< for free connections.
+ //!< (0 is infinite).
+ int delay_interval; //!< When we next do a
+ //!< cleanup. Initialized to
+ //!< cleanup_interval, and increase
+ //!< from there based on the delay.
+ int next_delay; //!< The next delay time.
+ //!< cleanup. Initialized to
+ //!< cleanup_interval, and decays
+ //!< from there.
uint64_t max_uses; //!< Maximum number of times a
//!< connection can be used before being
//!< closed.
- int lifetime; //!< How long a connection can be open
+ uint32_t lifetime; //!< How long a connection can be open
//!< before being closed (irrespective
//!< of whether it's idle or not).
- int idle_timeout; //!< How long a connection can be idle
+ uint32_t idle_timeout; //!< How long a connection can be idle
//!< before being closed.
bool trigger; //!< If true execute connection triggers
time_t last_spawned; //!< Last time we spawned a connection.
time_t last_failed; //!< Last time we tried to spawn a
//!< a connection but failed.
- time_t last_complained;//!< Last time we complained about
- //!< configuration parameters.
time_t last_throttled; //!< Last time we refused to spawn a
//!< connection because the last
//!< connection failed, or we were
uint64_t count; //!< Number of connections spawned over
//!< the lifetime of the pool.
- int num; //!< Number of connections in the pool.
+ uint32_t num; //!< Number of connections in the pool.
int active; //!< Number of currently reserved
//!< connections.
#endif
static const CONF_PARSER connection_config[] = {
- { "start", PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, start),
- 0, "5" },
- { "min", PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, min),
- 0, "5" },
- { "max", PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, max),
- 0, "10" },
- { "spare", PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, spare),
- 0, "3" },
- { "uses", PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, max_uses),
- 0, "0" },
- { "lifetime", PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, lifetime),
- 0, "0" },
- { "cleanup_delay", PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, cleanup_delay),
- 0, "5" },
- { "idle_timeout", PW_TYPE_INTEGER, offsetof(fr_connection_pool_t, idle_timeout),
- 0, "60" },
- { "spread", PW_TYPE_BOOLEAN, offsetof(fr_connection_pool_t, spread),
- 0, "no" },
+ { "start", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, start), "5" },
+ { "min", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, min), "5" },
+ { "max", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, max), "10" },
+ { "spare", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, spare), "3" },
+ { "uses", FR_CONF_OFFSET(PW_TYPE_INTEGER64, fr_connection_pool_t, max_uses), "0" },
+ { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, lifetime), "0" },
+ { "cleanup_delay", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, cleanup_interval), NULL},
+ { "cleanup_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, cleanup_interval), "30" },
+ { "idle_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, idle_timeout), "60" },
+ { "retry_delay", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, retry_delay), "1" },
+ { "spread", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_connection_pool_t, spread), "no" },
{ NULL, -1, 0, NULL, NULL }
};
* @param[in] this Connection to add.
*/
static void fr_connection_link_head(fr_connection_pool_t *pool,
- fr_connection_t *this)
+ fr_connection_t *this)
{
rad_assert(pool != NULL);
rad_assert(this != NULL);
* @param[in] this Connection to add.
*/
static void fr_connection_link_tail(fr_connection_pool_t *pool,
- fr_connection_t *this)
+ fr_connection_t *this)
{
rad_assert(pool != NULL);
rad_assert(this != NULL);
*
* @param[in] pool to modify.
* @param[in] now Current time.
+ * @param[in] in_use whether the new connection should be "in_use" or not
* @return the new connection struct or NULL on error.
*/
static fr_connection_t *fr_connection_spawn(fr_connection_pool_t *pool,
- time_t now)
+ time_t now, bool in_use)
{
fr_connection_t *this;
void *conn;
pthread_mutex_lock(&pool->mutex);
rad_assert(pool->num <= pool->max);
- if ((pool->last_failed == now) || pool->spawning) {
- int complain = false;
+ /*
+ * Don't spawn multiple connections at the same time.
+ */
+ if (pool->spawning) {
+ pthread_mutex_unlock(&pool->mutex);
+
+ ERROR("%s: Cannot open new connection, "
+ "connection spawning already in "
+ "progress", pool->log_prefix);
+ return NULL;
+ }
+
+ /*
+ * If the last attempt failed, wait a bit before
+ * retrying.
+ */
+ if (pool->last_failed && ((pool->last_failed + pool->retry_delay) > now)) {
+ bool complain = false;
if (pool->last_throttled != now) {
complain = true;
pthread_mutex_unlock(&pool->mutex);
- if (complain) {
- if (pool->spawning) {
- ERROR("%s: Cannot open new connection, "
- "connection spawning already in "
- "progress", pool->log_prefix);
- } else {
- ERROR("%s: Last connection failed, "
- "throttling connection spawn",
- pool->log_prefix);
- }
+ if (!RATE_LIMIT_ENABLED || complain) {
+ ERROR("%s: Last connection attempt failed, waiting %d seconds before retrying",
+ pool->log_prefix, pool->retry_delay);
}
return NULL;
INFO("%s: Opening additional connection (%" PRIu64 ")", pool->log_prefix, pool->count);
- this = rad_malloc(sizeof(*this));
- memset(this, 0, sizeof(*this));
-
/*
* This may take a long time, which prevents other
* threads from releasing connections. We don't care
ERROR("%s: Opening connection failed (%" PRIu64 ")", pool->log_prefix, pool->count);
pool->last_failed = now;
- free(this);
pool->spawning = false; /* atomic, so no lock is needed */
return NULL;
}
- this->created = now;
- this->connection = conn;
-
/*
* And lock the mutex again while we link the new
* connection back into the pool.
*/
pthread_mutex_lock(&pool->mutex);
- this->number = pool->count++;
- this->last_used = now;
- fr_connection_link_head(pool, this);
- pool->num++;
- pool->spawning = false;
- pool->last_spawned = time(NULL);
-
- pthread_mutex_unlock(&pool->mutex);
-
- if (pool->trigger) exec_trigger(NULL, pool->cs, "open", true);
-
- return this;
-}
-
-/** Add a new connection to the pool
- *
- * If conn is not NULL will attempt to add that connection handle to the pool.
- * If conn is NULL will attempt to spawn a new connection using the create
- * callback.
- *
- * @note Will call the 'open' trigger.
- *
- * @param[in,out] pool to add connection to.
- * @param[in] conn to add.
- * @return 0 if the connection wasn't added else 1.
- */
-int fr_connection_add(fr_connection_pool_t *pool, void *conn)
-{
- fr_connection_t *this;
-
- if (!pool) return 0;
-
- pthread_mutex_lock(&pool->mutex);
-
- if (!conn) {
- conn = pool->create(pool->ctx);
- if (!conn) {
- pthread_mutex_unlock(&pool->mutex);
- return 0;
- }
-
- INFO("%s: Opening connection successful (%" PRIu64 ")", pool->log_prefix, pool->count);
- }
-
- /*
- * Too many connections: can't add it.
- */
- if (pool->num >= pool->max) {
+ this = talloc_zero(pool, fr_connection_t);
+ if (!this) {
pthread_mutex_unlock(&pool->mutex);
- return 0;
+ return NULL;
}
- this = rad_malloc(sizeof(*this));
- memset(this, 0, sizeof(*this));
-
- this->created = time(NULL);
+ this->created = now;
this->connection = conn;
+ this->in_use = in_use;
this->number = pool->count++;
- this->last_used = time(NULL);
+ this->last_used = now;
fr_connection_link_head(pool, this);
pool->num++;
+ pool->spawning = false;
+ pool->last_spawned = time(NULL);
+ pool->delay_interval = pool->cleanup_interval;
+ pool->next_delay = pool->cleanup_interval;
+ pool->last_failed = 0;
pthread_mutex_unlock(&pool->mutex);
if (pool->trigger) exec_trigger(NULL, pool->cs, "open", true);
- return 1;
+ return this;
}
/** Close an existing connection.
static void fr_connection_close(fr_connection_pool_t *pool,
fr_connection_t *this)
{
- if (pool->trigger) exec_trigger(NULL, pool->cs, "close", true);
+ /*
+ * If it's in use, release it.
+ */
+ if (this->in_use) {
+#ifdef PTHREAD_DEBUG
+ pthread_t pthread_id = pthread_self();
+ rad_assert(pthread_equal(this->pthread_id, pthread_id) != 0);
+#endif
+ this->in_use = false;
- rad_assert(this->in_use == false);
+ rad_assert(pool->active > 0);
+ pool->active--;
+ }
+
+ if (pool->trigger) exec_trigger(NULL, pool->cs, "close", true);
fr_connection_unlink(pool, this);
pool->delete(pool->ctx, this->connection);
rad_assert(pool->num > 0);
pool->num--;
- free(this);
+ talloc_free(this);
}
/** Find a connection handle in the connection list
* order to find top of the parent structure.
*/
for (this = pool->head; this != NULL; this = this->next) {
- if (this->connection == conn) return this;
+ if (this->connection == conn) {
+#ifdef PTHREAD_DEBUG
+ pthread_t pthread_id;
+
+ pthread_id = pthread_self();
+ rad_assert(pthread_equal(this->pthread_id, pthread_id) != 0);
+#endif
+
+ rad_assert(this->in_use == true);
+ return this;
+ }
}
pthread_mutex_unlock(&pool->mutex);
this = fr_connection_find(pool, conn);
if (!this) return 0;
- /*
- * If it's in use, release it.
- */
- if (this->in_use) {
- rad_assert(this->in_use == true);
- this->in_use = false;
-
- rad_assert(pool->active > 0);
- pool->active--;
- }
-
INFO("%s: Deleting connection (%" PRIu64 ")", pool->log_prefix, this->number);
fr_connection_close(pool, this);
rad_assert(pool->tail == NULL);
rad_assert(pool->num == 0);
- free(pool->log_prefix);
- free(pool);
+ talloc_free(pool);
}
/** Create a new connection pool
fr_connection_create_t c,
fr_connection_alive_t a,
fr_connection_delete_t d,
- char *prefix)
+ char const *prefix)
{
- int i, lp_len;
+ uint32_t i;
fr_connection_pool_t *pool;
fr_connection_t *this;
CONF_SECTION *modules;
cs = cf_section_sub_find(parent, "pool");
if (!cs) cs = cf_section_sub_find(parent, "limit");
- pool = rad_malloc(sizeof(*pool));
- memset(pool, 0, sizeof(*pool));
+ if (cs) {
+ pool = talloc_zero(cs, fr_connection_pool_t);
+ } else {
+ pool = talloc_zero(parent, fr_connection_pool_t);
+ }
+ if (!pool) return NULL;
pool->cs = cs;
pool->ctx = ctx;
cs_name2 = cs_name1;
}
- lp_len = (sizeof(LOG_PREFIX) - 4) + strlen(cs_name1) + strlen(cs_name2);
- pool->log_prefix = rad_malloc(lp_len);
- snprintf(pool->log_prefix, lp_len, LOG_PREFIX, cs_name1,
- cs_name2);
+ pool->log_prefix = talloc_typed_asprintf(pool, LOG_PREFIX, cs_name1,
+ cs_name2);
}
} else { /* not a module configuration */
cs_name1 = cf_section_name1(parent);
- pool->log_prefix = strdup(cs_name1);
+ pool->log_prefix = talloc_typed_strdup(pool, cs_name1);
}
} else {
- pool->log_prefix = strdup(prefix);
+ pool->log_prefix = talloc_typed_strdup(pool, prefix);
}
DEBUG("%s: Initialising connection pool", pool->log_prefix);
pool->min = 5;
pool->max = 10;
pool->spare = 3;
- pool->cleanup_delay = 5;
+ pool->cleanup_interval = 30;
pool->idle_timeout = 60;
}
pool->idle_timeout = 0;
}
+ if ((pool->idle_timeout > 0) && (pool->cleanup_interval > pool->idle_timeout)) {
+ pool->cleanup_interval = pool->idle_timeout;
+ }
+
+ /*
+ * Don't open any connections. Instead, force the limits
+ * to only 1 connection.
+ *
+ */
+ if (check_config) {
+ pool->start = pool->min = pool->max = 1;
+ return pool;
+ }
+
/*
* Create all of the connections, unless the admin says
* not to.
*/
for (i = 0; i < pool->start; i++) {
- this = fr_connection_spawn(pool, now);
+ this = fr_connection_spawn(pool, now, false);
if (!this) {
error:
fr_connection_pool_delete(pool);
DEBUG("%s: Closing expired connection (%" PRIu64 "): Hit max_uses limit", pool->log_prefix,
this->number);
do_delete:
- if ((pool->num <= pool->min) &&
- (pool->last_complained < now)) {
- WARN("%s: You probably need to lower \"min\"", pool->log_prefix);
-
- pool->last_complained = now;
+ if (pool->num <= pool->min) {
+ RATE_LIMIT(WARN("%s: You probably need to lower \"min\"", pool->log_prefix));
}
fr_connection_close(pool, this);
return 0;
*/
static int fr_connection_pool_check(fr_connection_pool_t *pool)
{
- int spare, spawn;
+ uint32_t spawn, idle, extra;
time_t now = time(NULL);
fr_connection_t *this, *next;
return 1;
}
- spare = pool->num - pool->active;
+ /*
+ * Some idle connections are OK, if they're within the
+ * configured "spare" range. Any extra connections
+ * outside of that range can be closed.
+ */
+ idle = pool->num - pool->active;
+ if (idle <= pool->spare) {
+ extra = 0;
+ } else {
+ extra = idle - pool->spare;
+ }
- if ((pool->num < pool->max) && (spare < pool->spare)) {
- spawn = pool->spare - spare;
- if ((spawn + pool->num) > pool->max) {
- spawn = pool->max - pool->num;
+ /*
+ * The other end can close connections. If so, we'll
+ * have fewer than "min". When that happens, open more
+ * connections to enforce "min".
+ */
+ if (pool->num <= pool->min) {
+ if (pool->spawning) {
+ spawn = 0;
+ } else {
+ spawn = pool->min - pool->num;
}
- if (pool->spawning) spawn = 0;
+ extra = 0;
+
+ } else if (pool->num >= pool->max) {
+ /*
+ * Ensure we don't spawn more connections. If
+ * there are extra idle connections, we can
+ * delete all of them.
+ */
+ spawn = 0;
+ /* leave extra alone from above */
+
+ } else if (idle <= pool->spare) {
+ /*
+ * Not enough spare connections. Spawn a few.
+ * But cap the pool size at "max"
+ */
+ spawn = pool->spare - idle;
+ extra = 0;
- if (spawn) {
- pthread_mutex_unlock(&pool->mutex);
- fr_connection_spawn(pool, now); /* ignore return code */
- pthread_mutex_lock(&pool->mutex);
+ if ((pool->num + spawn) > pool->max) {
+ spawn = pool->max - pool->num;
}
+
+ } else if ((pool->min + extra) >= pool->num) {
+ /*
+ * If closing the extra connections would take us
+ * below "min", then don't do that. Cap the
+ * spare connections at the ones which will take
+ * us exactly to "min".
+ */
+ spawn = 0;
+ extra = pool->num - pool->min;
+
+ } else {
+ /*
+ * Closing the "extra" connections won't take us
+ * below "min". It's therefore safe to close
+ * them all.
+ */
+ spawn = 0;
+ /* leave extra alone from above */
+ }
+
+ if (spawn) {
+ pthread_mutex_unlock(&pool->mutex);
+ fr_connection_spawn(pool, now, false); /* ignore return code */
+ pthread_mutex_lock(&pool->mutex);
}
/*
* We haven't spawned connections in a while, and there
* are too many spare ones. Close the one which has been
- * idle for the longest.
+ * unused for the longest.
*/
- if ((now >= (pool->last_spawned + pool->cleanup_delay)) &&
- (spare > pool->spare)) {
- fr_connection_t *idle;
+ if (extra && (now >= (pool->last_spawned + pool->delay_interval))) {
+ fr_connection_t *found;
- idle = NULL;
+ found = NULL;
for (this = pool->tail; this != NULL; this = this->prev) {
if (this->in_use) continue;
- if (!idle ||
- (this->last_used < idle->last_used)) {
- idle = this;
+ if (!found ||
+ (this->last_used < found->last_used)) {
+ found = this;
}
}
- rad_assert(idle != NULL);
+ rad_assert(found != NULL);
- INFO("%s: Closing connection (%" PRIu64 "): Too many free connections (%d > %d)", pool->log_prefix,
- idle->number, spare, pool->spare);
- fr_connection_close(pool, idle);
+ INFO("%s: Closing connection (%" PRIu64 "), from %d unused connections", pool->log_prefix,
+ found->number, extra);
+ fr_connection_close(pool, found);
+
+ /*
+ * Decrease the delay for the next time we clean
+ * up.
+ */
+ pool->next_delay >>= 1;
+ if (pool->next_delay == 0) pool->next_delay = 1;
+ pool->delay_interval += pool->next_delay;
}
/*
return 1;
}
-/** Trigger connection check for a given connection or all connections
- *
- * If conn is not NULL then we call fr_connection_manage on the connection.
- * If conn is NULL we call fr_connection_pool_check on the pool.
- *
- * @note Only connections that are not in use will be closed.
- *
- * @see fr_connection_manage
- * @see fr_connection_pool_check
- * @param[in,out] pool to manage.
- * @param[in,out] conn to check.
- * @return 0 if the connection was closed, else 1.
- */
-int fr_connection_check(fr_connection_pool_t *pool, void *conn)
-{
- fr_connection_t *this;
- time_t now;
- int ret = 1;
-
- if (!pool) return 1;
-
- now = time(NULL);
- pthread_mutex_lock(&pool->mutex);
-
- if (!conn) return fr_connection_pool_check(pool);
-
- for (this = pool->head; this != NULL; this = this->next) {
- if (this->connection == conn) {
- ret = fr_connection_manage(pool, conn, now);
- break;
- }
- }
-
- pthread_mutex_unlock(&pool->mutex);
-
- return ret;
-}
-
-/** Reserve a connection in the connection pool
+/** Get a connection from the connection pool
*
- * Will attempt to find an unused connection in the connection pool, if one is
- * found, will mark it as in in use increment the number of active connections
- * and return the connection handle.
- *
- * If no free connections are found will attempt to spawn a new one, conditional
- * on a connection spawning not already being in progress, and not being at the
- * 'max' connection limit.
- *
- * @note fr_connection_release must be called once the caller has finished
- * using the connection.
- *
- * @see fr_connection_release
* @param[in,out] pool to reserve the connection from.
+ * @param[in] spawn whether to spawn a new connection
* @return a pointer to the connection handle, or NULL on error.
*/
-void *fr_connection_get(fr_connection_pool_t *pool)
+static void *fr_connection_get_internal(fr_connection_pool_t *pool, int spawn)
{
time_t now;
fr_connection_t *this, *next;
}
if (pool->num == pool->max) {
- int complain = false;
+ bool complain = false;
/*
* Rate-limit complaints.
pthread_mutex_unlock(&pool->mutex);
- if (complain) {
+ if (!RATE_LIMIT_ENABLED || complain) {
ERROR("%s: No connections available and at max connection limit", pool->log_prefix);
}
}
pthread_mutex_unlock(&pool->mutex);
- this = fr_connection_spawn(pool, now);
+
+ if (!spawn) return NULL;
+
+ this = fr_connection_spawn(pool, now, true); /* MY connection! */
if (!this) return NULL;
pthread_mutex_lock(&pool->mutex);
this->last_used = now;
this->in_use = true;
+#ifdef PTHREAD_DEBUG
+ this->pthread_id = pthread_self();
+#endif
pthread_mutex_unlock(&pool->mutex);
DEBUG("%s: Reserved connection (%" PRIu64 ")", pool->log_prefix, this->number);
return this->connection;
}
+
+/** Reserve a connection in the connection pool
+ *
+ * Will attempt to find an unused connection in the connection pool, if one is
+ * found, will mark it as in in use increment the number of active connections
+ * and return the connection handle.
+ *
+ * If no free connections are found will attempt to spawn a new one, conditional
+ * on a connection spawning not already being in progress, and not being at the
+ * 'max' connection limit.
+ *
+ * @note fr_connection_release must be called once the caller has finished
+ * using the connection.
+ *
+ * @see fr_connection_release
+ * @param[in,out] pool to reserve the connection from.
+ * @return a pointer to the connection handle, or NULL on error.
+ */
+void *fr_connection_get(fr_connection_pool_t *pool)
+{
+ return fr_connection_get_internal(pool, true);
+}
+
+/** Get the number of connections currently in the pool
+ *
+ * @param pool to count connections for.
+ * @return the number of connections in the pool
+ */
+int fr_connection_get_num(fr_connection_pool_t *pool)
+{
+ return pool->num;
+}
+
/** Release a connection
*
* Will mark a connection as unused and decrement the number of active
this = fr_connection_find(pool, conn);
if (!this) return;
- rad_assert(this->in_use == true);
this->in_use = false;
/*
* @see fr_connection_get
* @param[in,out] pool to reconnect the connection in.
* @param[in,out] conn to reconnect.
- * @return ew connection handle if successful else NULL.
+ * @return new connection handle if successful else NULL.
*/
void *fr_connection_reconnect(fr_connection_pool_t *pool, void *conn)
{
this = fr_connection_find(pool, conn);
if (!this) return NULL;
+ /*
+ * The pool is now locked.
+ */
conn_number = this->number;
- rad_assert(this->in_use == true);
-
DEBUG("%s: Reconnecting (%" PRIu64 ")", pool->log_prefix, conn_number);
new_conn = pool->create(pool->ctx);
if (!new_conn) {
- time_t now = time(NULL);
-
- if (pool->last_complained == now) {
- now = 0;
- } else {
- pool->last_complained = now;
- }
-
- this->in_use = false;
-
- rad_assert(pool->active > 0);
- pool->active--;
-
+ /*
+ * We can't create a new connection, so close
+ * this one.
+ */
fr_connection_close(pool, this);
- pthread_mutex_unlock(&pool->mutex);
/*
- * Can't create a new socket.
- * Try grabbing a pre-existing one.
+ * Maybe there's a connection which is unused and
+ * available. If so, return it.
*/
- new_conn = fr_connection_get(pool);
+ pthread_mutex_unlock(&pool->mutex);
+ new_conn = fr_connection_get_internal(pool, false);
if (new_conn) return new_conn;
- if (!now) return NULL;
-
- ERROR("%s: Failed to reconnect (%" PRIu64 "), and no other connections available", pool->log_prefix,
- conn_number);
-
+ RATE_LIMIT(ERROR("%s: Failed to reconnect (%" PRIu64 "), no free connections are available", pool->log_prefix,
+ conn_number));
return NULL;
}
+ if (pool->trigger) exec_trigger(NULL, pool->cs, "close", true);
pool->delete(pool->ctx, conn);
this->connection = new_conn;
pthread_mutex_unlock(&pool->mutex);
/*
* No pthreads, no mutex.
*/
-static int fr_crypt_init = 0;
+static bool fr_crypt_init = false;
static pthread_mutex_t fr_crypt_mutex;
#endif
/*
* Ensure we're thread-safe, as crypt() isn't.
*/
- if (fr_crypt_init == 0) {
+ if (fr_crypt_init == false) {
pthread_mutex_init(&fr_crypt_mutex, NULL);
- fr_crypt_init = 1;
+ fr_crypt_init = true;
}
pthread_mutex_lock(&fr_crypt_mutex);
#ifdef WITH_DETAIL
+extern bool check_config;
+
#define USEC (1000000)
static FR_NAME_NUMBER state_names[] = {
{ NULL, 0 }
};
+
/*
* If we're limiting outstanding packets, then mark the response
* as being sent.
*/
int detail_send(rad_listen_t *listener, REQUEST *request)
{
- int rtt;
- struct timeval now;
+#ifdef WITH_DETAIL_THREAD
+ char c = 0;
+#endif
listen_detail_t *data = listener->data;
rad_assert(request->listener == listener);
RDEBUG("Detail - No response configured for request %d. Will retry in %d seconds",
request->number, data->retry_interval);
+ } else {
+ int rtt;
+ struct timeval now;
+ /*
+ * We call gettimeofday a lot. But it should be OK,
+ * because there's nothing else to do.
+ */
+ gettimeofday(&now, NULL);
- radius_signal_self(RADIUS_SIGNAL_SELF_DETAIL);
- return 0;
- }
-
- /*
- * We call gettimeofday a lot. But it should be OK,
- * because there's nothing else to do.
- */
- gettimeofday(&now, NULL);
+ /*
+ * If we haven't sent a packet in the last second, reset
+ * the RTT.
+ */
+ now.tv_sec -= 1;
+ if (timercmp(&data->last_packet, &now, <)) {
+ data->has_rtt = false;
+ }
+ now.tv_sec += 1;
- /*
- * If we haven't sent a packet in the last second, reset
- * the RTT.
- */
- now.tv_sec -= 1;
- if (timercmp(&data->last_packet, &now, <)) {
- data->has_rtt = false;
- }
- now.tv_sec += 1;
+ /*
+ * Only one detail packet may be outstanding at a time,
+ * so it's safe to update some entries in the detail
+ * structure.
+ *
+ * We keep smoothed round trip time (SRTT), but not round
+ * trip timeout (RTO). We use SRTT to calculate a rough
+ * load factor.
+ */
+ rtt = now.tv_sec - request->packet->timestamp.tv_sec;
+ rtt *= USEC;
+ rtt += now.tv_usec;
+ rtt -= request->packet->timestamp.tv_usec;
- /*
- * Only one detail packet may be outstanding at a time,
- * so it's safe to update some entries in the detail
- * structure.
- *
- * We keep smoothed round trip time (SRTT), but not round
- * trip timeout (RTO). We use SRTT to calculate a rough
- * load factor.
- */
- rtt = now.tv_sec - request->packet->timestamp.tv_sec;
- rtt *= USEC;
- rtt += now.tv_usec;
- rtt -= request->packet->timestamp.tv_usec;
+ /*
+ * If we're proxying, the RTT is our processing time,
+ * plus the network delay there and back, plus the time
+ * on the other end to process the packet. Ideally, we
+ * should remove the network delays from the RTT, but we
+ * don't know what they are.
+ *
+ * So, to be safe, we over-estimate the total cost of
+ * processing the packet.
+ */
+ if (!data->has_rtt) {
+ data->has_rtt = true;
+ data->srtt = rtt;
+ data->rttvar = rtt / 2;
- /*
- * If we're proxying, the RTT is our processing time,
- * plus the network delay there and back, plus the time
- * on the other end to process the packet. Ideally, we
- * should remove the network delays from the RTT, but we
- * don't know what they are.
- *
- * So, to be safe, we over-estimate the total cost of
- * processing the packet.
- */
- if (!data->has_rtt) {
- data->has_rtt = true;
- data->srtt = rtt;
- data->rttvar = rtt / 2;
+ } else {
+ data->rttvar -= data->rttvar >> 2;
+ data->rttvar += (data->srtt - rtt);
+ data->srtt -= data->srtt >> 3;
+ data->srtt += rtt >> 3;
+ }
- } else {
- data->rttvar -= data->rttvar >> 2;
- data->rttvar += (data->srtt - rtt);
- data->srtt -= data->srtt >> 3;
- data->srtt += rtt >> 3;
- }
+ /*
+ * Calculate the time we wait before sending the next
+ * packet.
+ *
+ * rtt / (rtt + delay) = load_factor / 100
+ */
+ data->delay_time = (data->srtt * (100 - data->load_factor)) / (data->load_factor);
- /*
- * Calculate the time we wait before sending the next
- * packet.
- *
- * rtt / (rtt + delay) = load_factor / 100
- */
- data->delay_time = (data->srtt * (100 - data->load_factor)) / (data->load_factor);
+ /*
+ * Cap delay at no less than 4 packets/s. If the
+ * end system can't handle this, then it's very
+ * broken.
+ */
+ if (data->delay_time > (USEC / 4)) data->delay_time= USEC / 4;
- /*
- * Cap delay at 4 packets/s. If the end system can't
- * handle this, then it's very broken.
- */
- if (data->delay_time > (USEC / 4)) data->delay_time= USEC / 4;
+ RDEBUG3("Received response for request %d. Will read the next packet in %d seconds",
+ request->number, data->delay_time / USEC);
- RDEBUG3("Received response for request %d. Will read the next packet in %d seconds",
- request->number, data->delay_time / USEC);
+ data->last_packet = now;
+ data->signal = 1;
+ data->state = STATE_REPLIED;
+ data->counter++;
+ }
- data->last_packet = now;
- data->signal = 1;
- data->state = STATE_REPLIED;
- data->counter++;
+#ifdef WITH_DETAIL_THREAD
+ if (write(data->child_pipe[1], &c, 1) < 0) {
+ ERROR("Failed writing ack to reader thread: %s", fr_syserror(errno));
+ }
+#else
radius_signal_self(RADIUS_SIGNAL_SELF_DETAIL);
+#endif
return 0;
}
* this file will be read && processed before the
* file globbing is done.
*/
- this->fd = open(data->filename_work, O_RDWR);
- if (this->fd < 0) {
- bool free_filename = false;
- char *filename = data->filename;
-
- DEBUG2("Polling for detail file %s", filename);
-
- /*
- * Try reading the detail file. If it
- * doesn't exist, we can't do anything.
- *
- * Doing the stat will tell us if the file
- * exists, even if we don't have permissions
- * to read it.
- */
- if (stat(filename, &st) < 0) {
+ data->work_fd = open(data->filename_work, O_RDWR);
+ if (data->work_fd < 0) {
#ifndef HAVE_GLOB_H
- return 0;
+ return 0;
#else
- unsigned int i;
- int found;
- time_t chtime;
- glob_t files;
-
- memset(&files, 0, sizeof(files));
- if (glob(filename, 0, NULL, &files) != 0) {
- globfree(&files);
- return 0;
- }
-
- chtime = 0;
- found = -1;
- for (i = 0; i < files.gl_pathc; i++) {
- if (stat(files.gl_pathv[i], &st) < 0) continue;
-
- if ((i == 0) ||
- (st.st_ctime < chtime)) {
- chtime = st.st_ctime;
- found = i;
- }
- }
+ unsigned int i;
+ int found;
+ time_t chtime;
+ char const *filename;
+ glob_t files;
- if (found < 0) {
- globfree(&files);
- return 0;
- }
+ DEBUG2("Polling for detail file %s", data->filename);
- filename = strdup(files.gl_pathv[found]);
- free_filename = true;
+ memset(&files, 0, sizeof(files));
+ if (glob(data->filename, 0, NULL, &files) != 0) {
+ noop:
globfree(&files);
-#endif
+ return 0;
}
/*
- * Open it BEFORE we rename it, just to
- * be safe...
+ * Loop over the glob'd files, looking for the
+ * oldest one.
*/
- this->fd = open(filename, O_RDWR);
- if (this->fd < 0) {
- ERROR("Detail - Failed to open %s: %s",
- filename, strerror(errno));
- if (free_filename) free(filename);
- return 0;
+ chtime = 0;
+ found = -1;
+ for (i = 0; i < files.gl_pathc; i++) {
+ if (stat(files.gl_pathv[i], &st) < 0) continue;
+
+ if ((i == 0) || (st.st_ctime < chtime)) {
+ chtime = st.st_ctime;
+ found = i;
+ }
}
+ if (found < 0) goto noop;
+
/*
* Rename detail to detail.work
*/
+ filename = files.gl_pathv[found];
+
DEBUG("Detail - Renaming %s -> %s", filename, data->filename_work);
if (rename(filename, data->filename_work) < 0) {
ERROR("Detail - Failed renaming %s to %s: %s",
- filename, data->filename_work, strerror(errno));
- if (free_filename) free(filename);
- close(this->fd);
- this->fd = -1;
- return 0;
+ filename, data->filename_work, fr_syserror(errno));
+ goto noop;
}
+ globfree(&files); /* Shouldn't be using anything in files now */
+
/*
- * Ensure we don't leak memory.
+ * And try to open the filename.
*/
- if (free_filename) free(filename);
+ data->work_fd = open(data->filename_work, O_RDWR);
+ if (data->work_fd < 0) return 0;
+#endif
} /* else detail.work existed, and we opened it */
rad_assert(data->vps == NULL);
* t_rtt + t_delay wait for signal that the server is idle.
*
*/
+#ifndef WITH_DETAIL_THREAD
+static RADIUS_PACKET *detail_poll(rad_listen_t *listener);
+
int detail_recv(rad_listen_t *listener)
{
- char key[256], op[8], value[1024];
- vp_cursor_t cursor;
- VALUE_PAIR *vp;
- RADIUS_PACKET *packet;
- char buffer[2048];
+ RADIUS_PACKET *packet;
listen_detail_t *data = listener->data;
/*
*/
if (data->signal) return 0;
+ packet = detail_poll(listener);
+ if (!packet) return -1;
+
+ /*
+ * Don't bother doing limit checks, etc.
+ */
+ if (!request_receive(listener, packet, &data->detail_client,
+ rad_accounting)) {
+ rad_free(&packet);
+ data->state = STATE_NO_REPLY; /* try again later */
+ return 0;
+ }
+
+ return 1;
+}
+#else
+int detail_recv(rad_listen_t *listener)
+{
+ ssize_t rcode;
+ RADIUS_PACKET *packet;
+ listen_detail_t *data = listener->data;
+
+ /*
+ * Block until there's a packet ready.
+ */
+ rcode = read(data->master_pipe[0], &packet, sizeof(packet));
+ if (rcode <= 0) return rcode;
+
+ rad_assert(packet != NULL);
+
+ if (!request_receive(listener, packet, &data->detail_client,
+ rad_accounting)) {
+ char c = 0;
+ rad_free(&packet);
+ data->state = STATE_NO_REPLY; /* try again later */
+ if (write(data->child_pipe[1], &c, 1) < 0) {
+ ERROR("Failed writing ack to reader thread: %s", fr_syserror(errno));
+ }
+ }
+
+ /*
+ * Wait for the child thread to write an answer to the pipe
+ */
+ return 0;
+}
+#endif
+
+static RADIUS_PACKET *detail_poll(rad_listen_t *listener)
+{
+ char key[256], op[8], value[1024];
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+ RADIUS_PACKET *packet;
+ char buffer[2048];
+ listen_detail_t *data = listener->data;
+
switch (data->state) {
case STATE_UNOPENED:
open_file:
- rad_assert(listener->fd < 0);
+ rad_assert(data->work_fd < 0);
- if (!detail_open(listener)) return 0;
+ if (!detail_open(listener)) return NULL;
rad_assert(data->state == STATE_UNLOCKED);
- rad_assert(listener->fd >= 0);
+ rad_assert(data->work_fd >= 0);
/* FALL-THROUGH */
* "ping-pongs" between radiusd &
* radrelay.
*/
- if (rad_lockfd_nonblock(listener->fd, 0) < 0) {
+ if (rad_lockfd_nonblock(data->work_fd, 0) < 0) {
/*
* Close the FD. The main loop
* will wake up in a second and
* try again.
*/
- close(listener->fd);
- listener->fd = -1;
+ close(data->work_fd);
+ data->work_fd = -1;
data->state = STATE_UNOPENED;
- return 0;
+ return NULL;
}
- data->fp = fdopen(listener->fd, "r");
+ data->fp = fdopen(data->work_fd, "r");
if (!data->fp) {
ERROR("FATAL: Failed to re-open detail file %s: %s",
- data->filename, strerror(errno));
+ data->filename, fr_syserror(errno));
fr_exit(1);
}
{
struct stat buf;
- if (fstat(listener->fd, &buf) < 0) {
+ if (fstat(data->work_fd, &buf) < 0) {
ERROR("Failed to stat "
"detail file %s: %s",
- data->filename,
- strerror(errno));
+ data->filename,
+ fr_syserror(errno));
- goto cleanup;
+ goto cleanup;
}
if (((off_t) ftell(data->fp)) == buf.st_size) {
goto cleanup;
unlink(data->filename_work);
if (data->fp) fclose(data->fp);
data->fp = NULL;
- listener->fd = -1;
+ data->work_fd = -1;
data->state = STATE_UNOPENED;
rad_assert(data->vps == NULL);
radius_signal_self(RADIUS_SIGNAL_SELF_EXIT);
}
- return 0;
+ return NULL;
}
/*
* retry it.
*/
case STATE_RUNNING:
- if (time(NULL) < (data->running + data->retry_interval)) {
- return 0;
+ if (time(NULL) < (data->running + (int)data->retry_interval)) {
+ return NULL;
}
DEBUG("No response to detail request. Retrying");
- data->state = STATE_NO_REPLY;
/* FALL-THROUGH */
/*
goto do_header;
}
- paircursor(&cursor, &data->vps);
+ fr_cursor_init(&cursor, &data->vps);
/*
* Read a header, OR a value-pair.
*
* FIXME: print an error for badly formatted attributes?
*/
- if (sscanf(buffer, "%255s %8s %1023s", key, op, value) != 3) {
- WDEBUG2("Skipping badly formatted line %s",
+ if (sscanf(buffer, "%255s %7s %1023s", key, op, value) != 3) {
+ WARN("Skipping badly formatted line %s",
buffer);
continue;
}
*/
if (!strcasecmp(key, "Client-IP-Address")) {
data->client_ip.af = AF_INET;
- if (ip_hton(value, AF_INET, &data->client_ip) < 0) {
+ if (ip_hton(&data->client_ip, AF_INET, value, false) < 0) {
ERROR("Failed parsing Client-IP-Address");
pairfree(&data->vps);
if (vp) {
vp->vp_date = (uint32_t) data->timestamp;
vp->type = VT_DATA;
- pairinsert(&cursor, vp);
+ fr_cursor_insert(&cursor, vp);
}
continue;
}
vp = NULL;
if ((userparse(data, buffer, &vp) > 0) &&
(vp != NULL)) {
- pairinsert(&cursor, vp);
+ fr_cursor_insert(&cursor, vp);
}
}
if (!data->vps) {
data->state = STATE_HEADER;
if (!data->fp || feof(data->fp)) goto cleanup;
- return 0;
+ return NULL;
}
/*
packet->sockfd = -1;
packet->src_ipaddr.af = AF_INET;
packet->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_NONE);
- packet->code = PW_ACCOUNTING_REQUEST;
+ packet->code = PW_CODE_ACCOUNTING_REQUEST;
gettimeofday(&packet->timestamp, NULL);
/*
if (debug_flag) {
fr_printf_log("detail_recv: Read packet from %s\n", data->filename_work);
- for (vp = paircursor(&cursor, &packet->vps);
+ for (vp = fr_cursor_init(&cursor, &packet->vps);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
debug_pair(vp);
}
}
- /*
- * Don't bother doing limit checks, etc.
- */
- if (!request_receive(listener, packet, &data->detail_client,
- rad_accounting)) {
- rad_free(&packet);
- data->state = STATE_NO_REPLY; /* try again later */
- return 0;
- }
-
data->state = STATE_RUNNING;
data->running = packet->timestamp.tv_sec;
- return 1;
+ return packet;
}
-
/*
* Free detail-specific stuff.
*/
{
listen_detail_t *data = this->data;
- talloc_free(data->filename);
- data->filename = NULL;
- pairfree(&data->vps);
+#ifdef WITH_DETAIL_THREAD
+ if (!check_config) {
+ ssize_t ret;
+ void *arg = NULL;
+
+ /*
+ * Mark the child pipes as unusable
+ */
+ close(data->child_pipe[0]);
+ close(data->child_pipe[1]);
+ data->child_pipe[0] = -1;
+
+ /*
+ * Tell it to stop (interrupting it's sleep)
+ */
+ pthread_kill(data->pthread_id, SIGTERM);
+
+ /*
+ * Wait for it to acknowledge that it's stopped.
+ */
+ ret = read(data->master_pipe[0], &arg, sizeof(arg));
+ if (ret < 0) {
+ ERROR("Reader thread exited without informing the master: %s", fr_syserror(errno));
+ } else if (ret != sizeof(arg)) {
+ ERROR("Invalid thread pointer received from reader thread during exit");
+ ERROR("Expected %zu bytes, got %zi bytes", sizeof(arg), ret);
+ }
+
+ close(data->master_pipe[0]);
+ close(data->master_pipe[1]);
+
+ if (arg) pthread_join(data->pthread_id, &arg);
+ }
+#endif
if (data->fp != NULL) {
fclose(data->fp);
this->server);
}
+
/*
- * Overloaded to return delay times.
+ * Delay while waiting for a file to be ready
*/
-int detail_encode(rad_listen_t *this, UNUSED REQUEST *request)
+static int detail_delay(listen_detail_t *data)
{
- listen_detail_t *data = this->data;
+ int delay = (data->poll_interval - 1) * USEC;
/*
- * We haven't sent a packet... delay things a bit.
+ * Add +/- 0.25s of jitter
*/
- if (!data->signal) {
- int delay = (data->poll_interval - 1) * USEC;
+ delay += (USEC * 3) / 4;
+ delay += fr_rand() % (USEC / 2);
- /*
- * Add +/- 0.25s of jitter
- */
- delay += (USEC * 3) / 4;
- delay += fr_rand() % (USEC / 2);
+ DEBUG2("Detail listener %s state %s waiting %d.%06d sec",
+ data->filename,
+ fr_int2str(state_names, data->state, "?"),
+ (delay / USEC), delay % USEC);
- DEBUG2("Detail listener %s state %s signalled %d waiting %d.%06d sec",
- data->filename,
- fr_int2str(state_names, data->state, "?"), data->signal,
- (delay / USEC), delay % USEC);
+ return delay;
+}
- return delay;
- }
+/*
+ * Overloaded to return delay times.
+ */
+int detail_encode(UNUSED rad_listen_t *this, UNUSED REQUEST *request)
+{
+#ifdef WITH_DETAIL_THREAD
+ return 0;
+#else
+ listen_detail_t *data = this->data;
+
+ /*
+ * We haven't sent a packet... delay things a bit.
+ */
+ if (!data->signal) return detail_delay(data);
data->signal = 0;
data->delay_time % USEC);
return data->delay_time;
+#endif
}
-
/*
* Overloaded to return "should we fix delay times"
*/
-int detail_decode(rad_listen_t *this, UNUSED REQUEST *request)
+int detail_decode(UNUSED rad_listen_t *this, UNUSED REQUEST *request)
{
+#ifdef WITH_DETAIL_THREAD
+ return 0;
+#else
listen_detail_t *data = this->data;
return data->signal;
+#endif
}
+#ifdef WITH_DETAIL_THREAD
+static void *detail_handler_thread(void *arg)
+{
+ char c;
+ rad_listen_t *this = arg;
+ listen_detail_t *data = this->data;
+
+ while (true) {
+ RADIUS_PACKET *packet;
+
+ while ((packet = detail_poll(this)) == NULL) {
+ usleep(detail_delay(data));
+
+ /*
+ * If we're supposed to exit then tell
+ * the master thread we've exited.
+ */
+ if (data->child_pipe[0] < 0) {
+ packet = NULL;
+ if (write(data->master_pipe[1], &packet, sizeof(packet)) < 0) {
+ ERROR("Failed writing exit status to master: %s", fr_syserror(errno));
+ }
+ return NULL;
+ }
+ }
+
+ /*
+ * Keep retrying forever.
+ *
+ * FIXME: cap the retries.
+ */
+ do {
+ if (write(data->master_pipe[1], &packet, sizeof(packet)) < 0) {
+ ERROR("Failed passing detail packet pointer to master: %s", fr_syserror(errno));
+ }
+
+ if (read(data->child_pipe[0], &c, 1) < 0) {
+ ERROR("Failed getting detail packet ack from master: %s", fr_syserror(errno));
+ break;
+ }
+
+ if (data->delay_time > 0) usleep(data->delay_time);
+ } while (data->state != STATE_REPLIED);
+ }
+
+ return NULL;
+}
+#endif
+
+
static const CONF_PARSER detail_config[] = {
- { "detail", PW_TYPE_FILE_OUTPUT | PW_TYPE_DEPRECATED,
- offsetof(listen_detail_t, filename), NULL, NULL },
- { "filename", PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED,
- offsetof(listen_detail_t, filename), NULL, NULL },
- { "load_factor", PW_TYPE_INTEGER,
- offsetof(listen_detail_t, load_factor), NULL, STRINGIFY(10)},
- { "poll_interval", PW_TYPE_INTEGER,
- offsetof(listen_detail_t, poll_interval), NULL, STRINGIFY(1)},
- { "retry_interval", PW_TYPE_INTEGER,
- offsetof(listen_detail_t, retry_interval), NULL, STRINGIFY(30)},
- { "one_shot", PW_TYPE_BOOLEAN,
- offsetof(listen_detail_t, one_shot), NULL, NULL},
- { "max_outstanding", PW_TYPE_INTEGER,
- offsetof(listen_detail_t, load_factor), NULL, NULL},
+ { "detail", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_DEPRECATED, listen_detail_t, filename), NULL },
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED, listen_detail_t, filename), NULL },
+ { "load_factor", FR_CONF_OFFSET(PW_TYPE_INTEGER, listen_detail_t, load_factor), STRINGIFY(10) },
+ { "poll_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, listen_detail_t, poll_interval), STRINGIFY(1) },
+ { "retry_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, listen_detail_t, retry_interval), STRINGIFY(30) },
+ { "one_shot", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, listen_detail_t, one_shot), NULL },
+ { "max_outstanding", FR_CONF_OFFSET(PW_TYPE_INTEGER, listen_detail_t, load_factor), NULL },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
-extern bool check_config;
-
/*
* Parse a detail section.
*/
RADCLIENT *client;
char buffer[2048];
- if (check_config) return 0;
-
data = this->data;
rcode = cf_section_parse(cs, data, detail_config);
return -1;
}
+ if (check_config) return 0;
+
if (data->max_outstanding == 0) data->max_outstanding = 1;
/*
snprintf(buffer, sizeof(buffer), "%s.work", data->filename);
}
- free(data->filename_work);
- data->filename_work = strdup(buffer); /* FIXME: leaked */
+ data->filename_work = talloc_strdup(data, buffer);
+ data->work_fd = -1;
data->vps = NULL;
data->fp = NULL;
data->state = STATE_UNOPENED;
memset(client, 0, sizeof(*client));
client->ipaddr.af = AF_INET;
client->ipaddr.ipaddr.ip4addr.s_addr = INADDR_NONE;
- client->prefix = 0;
+ client->ipaddr.prefix = 0;
client->longname = client->shortname = data->filename;
client->secret = client->shortname;
- client->nas_type = strdup("none");
+ client->nas_type = talloc_strdup(data, "none"); /* Part of 'data' not dynamically allocated */
+
+#ifdef WITH_DETAIL_THREAD
+ /*
+ * Create the communication pipes.
+ */
+ if (pipe(data->master_pipe) < 0) {
+ ERROR("radiusd: Error opening internal pipe: %s",
+ fr_syserror(errno));
+ fr_exit(1);
+ }
+
+ if (pipe(data->child_pipe) < 0) {
+ ERROR("radiusd: Error opening internal pipe: %s",
+ fr_syserror(errno));
+ fr_exit(1);
+ }
+
+ pthread_create(&data->pthread_id, NULL, detail_handler_thread, this);
+
+ this->fd = data->master_pipe[0];
+#endif
return 0;
}
#ifdef WITH_EVAL_DEBUG
#define EVAL_DEBUG(fmt, ...) printf("EVAL: ");printf(fmt, ## __VA_ARGS__);printf("\n");fflush(stdout)
+
+static FR_NAME_NUMBER const template_names[] = {
+ { "literal", VPT_TYPE_LITERAL },
+ { "xlat", VPT_TYPE_XLAT },
+ { "attr", VPT_TYPE_ATTR },
+ { "list", VPT_TYPE_LIST },
+ { "regex", VPT_TYPE_REGEX },
+ { "exec", VPT_TYPE_EXEC },
+ { "data", VPT_TYPE_DATA },
+ { "xlat", VPT_TYPE_XLAT_STRUCT },
+ { "regex", VPT_TYPE_REGEX_STRUCT },
+ { NULL, 0 }
+};
#else
#define EVAL_DEBUG(...)
#endif
-static const FR_NAME_NUMBER modreturn_table[] = {
+FR_NAME_NUMBER const modreturn_table[] = {
{ "reject", RLM_MODULE_REJECT },
{ "fail", RLM_MODULE_FAIL },
{ "ok", RLM_MODULE_OK },
{
char const *p = string;
+ rad_assert(p != NULL);
+
if (*p == '-') p++;
while (isdigit((int) *p)) p++;
static int radius_expand_tmpl(char **out, REQUEST *request, value_pair_tmpl_t const *vpt)
{
VALUE_PAIR *vp;
+ int ret;
*out = NULL;
rad_assert(vpt->type != VPT_TYPE_LIST);
switch (vpt->type) {
case VPT_TYPE_LITERAL:
EVAL_DEBUG("TMPL LITERAL");
- *out = talloc_strdup(request, vpt->name);
+ *out = talloc_typed_strdup(request, vpt->name);
break;
case VPT_TYPE_EXEC:
case VPT_TYPE_REGEX:
EVAL_DEBUG("TMPL REGEX");
- if (strchr(vpt->name, '%') == NULL) {
- *out = talloc_strdup(request, vpt->name);
- break;
+ /* Error in expansion, this is distinct from zero length expansion */
+ if (radius_axlat(out, request, vpt->name, NULL, NULL) < 0) {
+ rad_assert(!*out);
+ return -1;
}
- /* FALL-THROUGH */
+ break;
case VPT_TYPE_XLAT:
EVAL_DEBUG("TMPL XLAT");
}
break;
- case VPT_TYPE_ATTR:
- EVAL_DEBUG("TMPL ATTR");
- vp = radius_vpt_get_vp(request, vpt);
- if (!vp) {
+ case VPT_TYPE_XLAT_STRUCT:
+ EVAL_DEBUG("TMPL XLAT_STRUCT");
+ /* Error in expansion, this is distinct from zero length expansion */
+ if (radius_axlat_struct(out, request, vpt->vpt_xlat, NULL, NULL) < 0) {
+ rad_assert(!*out);
return -1;
}
- *out = vp_aprint(request, vp);
+ RDEBUG2("EXPAND %s", vpt->name); /* xlat_struct doesn't do this */
+ RDEBUG2(" --> %s", *out);
+ break;
+
+ case VPT_TYPE_ATTR:
+ EVAL_DEBUG("TMPL ATTR");
+ ret = radius_tmpl_get_vp(&vp, request, vpt);
+ if (ret < 0) return ret;
+
+ *out = vp_aprint_value(request, vp);
if (!*out) {
return -1;
}
break;
case VPT_TYPE_DATA:
+ case VPT_TYPE_REGEX_STRUCT:
rad_assert(0 == 1);
/* FALL-THROUGH */
case VPT_TYPE_ATTR:
case VPT_TYPE_LIST:
- if (radius_vpt_get_vp(request, vpt) != NULL) {
- rcode = true;
- } else {
+ if (radius_tmpl_get_vp(NULL, request, vpt) < 0) {
rcode = false;
+ } else {
+ rcode = true;
}
break;
* FIXME: expand the strings
* if not empty, return!
*/
+ case VPT_TYPE_XLAT_STRUCT:
case VPT_TYPE_XLAT:
case VPT_TYPE_EXEC:
if (!*vpt->name) return false;
* Can't have a bare ... (/foo/) ...
*/
case VPT_TYPE_REGEX:
+ case VPT_TYPE_REGEX_STRUCT:
EVAL_DEBUG("FAIL %d", __LINE__);
rad_assert(0 == 1);
/* FALL-THROUGH */
}
-static int do_regex(REQUEST *request, char const *lhs, char const *rhs, bool iflag)
+static int do_regex(REQUEST *request, value_pair_map_t const *map)
{
- int compare;
- int cflags = REG_EXTENDED;
- regex_t reg;
+ int compare, rcode, ret;
+ regex_t reg, *preg;
+ char *lhs, *rhs;
regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];
- if (iflag) cflags |= REG_ICASE;
-
/*
- * Include substring matches.
+ * Expand and then compile it.
*/
- compare = regcomp(®, rhs, cflags);
- if (compare != 0) {
- if (debug_flag) {
- char errbuf[128];
+ switch (map->src->type) {
+ case VPT_TYPE_REGEX:
+ rcode = radius_expand_tmpl(&rhs, request, map->src);
+ if (rcode < 0) {
+ EVAL_DEBUG("FAIL %d", __LINE__);
+ return -1;
+ }
+ rad_assert(rhs != NULL);
- regerror(compare, ®, errbuf, sizeof(errbuf));
- EDEBUG("Failed compiling regular expression: %s", errbuf);
+ compare = regcomp(®, rhs, REG_EXTENDED | (map->src->vpt_iflag ? REG_ICASE : 0));
+ if (compare != 0) {
+ if (debug_flag) {
+ char errbuf[128];
+
+ regerror(compare, ®, errbuf, sizeof(errbuf));
+ ERROR("Failed compiling regular expression: %s", errbuf);
+ }
+ EVAL_DEBUG("FAIL %d", __LINE__);
+ return -1;
}
- EVAL_DEBUG("FAIL %d", __LINE__);
+
+ preg = ®
+ break;
+
+ case VPT_TYPE_REGEX_STRUCT:
+ preg = map->src->vpt_preg;
+ break;
+
+ default:
+ rad_assert(0);
return -1;
}
- memset(&rxmatch, 0, sizeof(rxmatch)); /* regexec does not seem to initialise unused elements */
- compare = regexec(®, lhs, REQUEST_MAX_REGEX + 1, rxmatch, 0);
- regfree(®);
+ rcode = radius_expand_tmpl(&lhs, request, map->dst);
+ if (rcode < 0) {
+ EVAL_DEBUG("FAIL %d", __LINE__);
+ ret = -1;
+ goto finish;
+ }
+ rad_assert(lhs != NULL);
+
+ /*
+ * regexec doesn't initialise unused elements
+ */
+ memset(&rxmatch, 0, sizeof(rxmatch));
+ compare = regexec(preg, lhs, REQUEST_MAX_REGEX + 1, rxmatch, 0);
rad_regcapture(request, compare, lhs, rxmatch);
+ ret = (compare == 0);
- return (compare == 0);
+finish:
+ /*
+ * regcomp allocs extra memory for the expression, so if the
+ * result wasn't cached we need to free it here.
+ */
+ if (preg == ®) regfree(®);
+
+ return ret;
}
/*
if (!vp) return NULL;
if (vpt->type == VPT_TYPE_DATA) {
- rad_assert(vp->da->type == vpt->da->type);
- memcpy(&vp->data, vpt->vpd, sizeof(vp->data));
- vp->length = vpt->length;
+ rad_assert(vp->da->type == vpt->vpt_da->type);
+ memcpy(&vp->data, vpt->vpt_value, sizeof(vp->data));
+ vp->length = vpt->vpt_length;
return vp;
}
return NULL;
}
- if (!pairparsevalue(vp, str)) {
+ if ((pairparsevalue(vp, str, 0) < 0)) {
talloc_free(str);
pairfree(&vp);
return NULL;
return vp;
}
+/*
+ * Copy data from src to dst, where the attributes are of
+ * different type.
+ */
+static int do_cast_copy(VALUE_PAIR *dst, VALUE_PAIR const *src)
+{
+ rad_assert(dst->da->type != src->da->type);
+
+ if (dst->da->type == PW_TYPE_STRING) {
+ dst->vp_strvalue = vp_aprint_value(dst, src);
+ dst->length = strlen(dst->vp_strvalue);
+ return 0;
+ }
+
+ if (dst->da->type == PW_TYPE_OCTETS) {
+ if (src->da->type == PW_TYPE_STRING) {
+ pairmemcpy(dst, src->vp_octets, src->length); /* Copy embedded NULLs */
+ } else {
+ pairmemcpy(dst, (uint8_t const *) &src->data, src->length);
+ }
+ return 0;
+ }
+
+ if (src->da->type == PW_TYPE_STRING) {
+ return pairparsevalue(dst, src->vp_strvalue, 0);
+ }
+
+ if ((src->da->type == PW_TYPE_INTEGER64) &&
+ (dst->da->type == PW_TYPE_ETHERNET)) {
+ uint8_t array[8];
+ uint64_t i;
+
+ i = htonll(src->vp_integer64);
+ memcpy(array, &i, 8);
+
+ /*
+ * For OUIs in the DB.
+ */
+ if ((array[0] != 0) || (array[1] != 0)) return -1;
+
+ memcpy(&dst->vp_ether, &array[2], 6);
+ dst->length = 6;
+ return 0;
+ }
+
+ /*
+ * The attribute we've found has to have a size which is
+ * compatible with the type of the destination cast.
+ */
+ if ((src->length < dict_attr_sizes[dst->da->type][0]) ||
+ (src->length > dict_attr_sizes[dst->da->type][1])) {
+ EVAL_DEBUG("Casted attribute is wrong size (%u)", (unsigned int) src->length);
+ return -1;
+ }
+
+ if (src->da->type == PW_TYPE_OCTETS) {
+ switch (dst->da->type) {
+ case PW_TYPE_INTEGER64:
+ dst->vp_integer = ntohll(*(uint64_t const *) src->vp_octets);
+ break;
+
+
+ case PW_TYPE_INTEGER:
+ case PW_TYPE_DATE:
+ case PW_TYPE_SIGNED:
+ dst->vp_integer = ntohl(*(uint32_t const *) src->vp_octets);
+ break;
+
+ case PW_TYPE_SHORT:
+ dst->vp_integer = ntohs(*(uint16_t const *) src->vp_octets);
+ break;
+
+ case PW_TYPE_BYTE:
+ dst->vp_integer = src->vp_octets[0];
+ break;
+
+ default:
+ memcpy(&dst->data, src->vp_octets, src->length);
+ break;
+ }
+
+ dst->length = src->length;
+ return 0;
+ }
+
+ /*
+ * Convert host order to network byte order.
+ */
+ if ((dst->da->type == PW_TYPE_IPV4_ADDR) &&
+ ((src->da->type == PW_TYPE_INTEGER) ||
+ (src->da->type == PW_TYPE_DATE) ||
+ (src->da->type == PW_TYPE_SIGNED))) {
+ dst->vp_ipaddr = htonl(src->vp_integer);
+
+ } else if ((src->da->type == PW_TYPE_IPV4_ADDR) &&
+ ((dst->da->type == PW_TYPE_INTEGER) ||
+ (dst->da->type == PW_TYPE_DATE) ||
+ (dst->da->type == PW_TYPE_SIGNED))) {
+ dst->vp_integer = htonl(src->vp_ipaddr);
+
+ } else { /* they're of the same byte order */
+ memcpy(&dst->data, &src->data, src->length);
+ }
+
+ dst->length = src->length;
+
+ return 0;
+}
+
+
/** Evaluate a map
*
* @param[in] request the REQUEST
rad_assert(map->dst->type != VPT_TYPE_LIST);
rad_assert(map->src->type != VPT_TYPE_LIST);
rad_assert(map->dst->type != VPT_TYPE_REGEX);
+ rad_assert(map->dst->type != VPT_TYPE_REGEX_STRUCT);
+
+ EVAL_DEBUG("Map %s ? %s",
+ fr_int2str(template_names, map->dst->type, "???"),
+ fr_int2str(template_names, map->src->type, "???"));
/*
* Verify regexes.
*/
- if (map->src->type == VPT_TYPE_REGEX) {
+ if ((map->src->type == VPT_TYPE_REGEX) ||
+ (map->src->type == VPT_TYPE_REGEX_STRUCT)) {
rad_assert(map->op == T_OP_REG_EQ);
} else {
rad_assert(!((map->op == T_OP_REG_EQ) || (map->op == T_OP_REG_NE)));
VALUE_PAIR *lhs_vp, *rhs_vp;
EVAL_DEBUG("ATTR to ATTR");
- lhs_vp = radius_vpt_get_vp(request, map->dst);
- rhs_vp = radius_vpt_get_vp(request, map->src);
-
- if (!lhs_vp || !rhs_vp) return false;
+ if ((radius_tmpl_get_vp(&lhs_vp, request, map->dst) < 0) ||
+ (radius_tmpl_get_vp(&rhs_vp, request, map->src) < 0)) return false;
return paircmp_op(lhs_vp, map->op, rhs_vp);
}
if (c->cast) {
VALUE_PAIR *lhs_vp, *rhs_vp;
- lhs_vp = get_cast_vp(request, map->dst, c->cast);
+ /*
+ * Try to copy data from the VP which is being
+ * casted, instead of printing it to a string and
+ * then re-parsing it.
+ */
+ if (map->dst->type == VPT_TYPE_ATTR) {
+ VALUE_PAIR *cast_vp;
+
+ if (radius_tmpl_get_vp(&cast_vp, request, map->dst) < 0) return false;
+
+ lhs_vp = pairalloc(request, c->cast);
+ if (!lhs_vp) return false;
+
+ /*
+ * In a separate function for clarity
+ */
+ if (do_cast_copy(lhs_vp, cast_vp) < 0) {
+ talloc_free(lhs_vp);
+ return false;
+ }
+
+ } else {
+ lhs_vp = get_cast_vp(request, map->dst, c->cast);
+ }
if (!lhs_vp) return false;
/*
* VP, and return that.
*/
if (map->src->type == VPT_TYPE_ATTR) {
- rhs_vp = radius_vpt_get_vp(request, map->src);
+ if (radius_tmpl_get_vp(&rhs_vp, request, map->src) < 0) return false;
} else {
rhs_vp = get_cast_vp(request, map->src, c->cast);
}
if (!rhs_vp) return false;
- EVAL_DEBUG("CAST to ...");
+ EVAL_DEBUG("CAST to %s",
+ fr_int2str(dict_attr_types,
+ c->cast->type, "?Unknown?"));
rcode = paircmp_op(lhs_vp, map->op, rhs_vp);
pairfree(&lhs_vp);
*/
if ((map->dst->type == VPT_TYPE_ATTR) &&
(map->src->type != VPT_TYPE_REGEX) &&
+ (map->src->type != VPT_TYPE_REGEX_STRUCT) &&
(c->pass2_fixup == PASS2_PAIRCOMPARE)) {
- int ret;
+ int ret;
VALUE_PAIR *lhs_vp;
EVAL_DEBUG("virtual ATTR to DATA");
- lhs_vp = get_cast_vp(request, map->src, map->dst->da);
+ lhs_vp = get_cast_vp(request, map->src, map->dst->vpt_da);
if (!lhs_vp) return false;
/*
EVAL_DEBUG("ATTR to DATA");
- lhs_vp = radius_vpt_get_vp(request, map->dst);
- if (!lhs_vp) return false;
+ if (radius_tmpl_get_vp(&lhs_vp, request, map->dst) < 0) return false;
- rhs_vp = get_cast_vp(request, map->src, map->dst->da);
+ rhs_vp = get_cast_vp(request, map->src, map->dst->vpt_da);
if (!rhs_vp) return false;
#ifdef WITH_EVAL_DEBUG
rad_assert(map->src->type != VPT_TYPE_DATA);
rad_assert(map->dst->type != VPT_TYPE_DATA);
+#ifdef HAVE_REGEX_H
+ /*
+ * Parse regular expressions.
+ */
+ if ((map->src->type == VPT_TYPE_REGEX) ||
+ (map->src->type == VPT_TYPE_REGEX_STRUCT)) {
+ return do_regex(request, map);
+ }
+#endif
+
/*
* The RHS now needs to be expanded into a string.
*/
EVAL_DEBUG("FAIL %d", __LINE__);
return -1;
}
+ rad_assert(rhs != NULL);
/*
* User-Name == FOO
*
* The LHS may be a virtual attribute, too.
*/
- if ((map->dst->type == VPT_TYPE_ATTR) &&
- (map->src->type != VPT_TYPE_REGEX)) {
+ if (map->dst->type == VPT_TYPE_ATTR) {
VALUE_PAIR *lhs_vp, *rhs_vp;
EVAL_DEBUG("ATTR to non-REGEX");
/*
* No LHS means no match
*/
- lhs_vp = radius_vpt_get_vp(request, map->dst);
- if (!lhs_vp) {
+ if (radius_tmpl_get_vp(&lhs_vp, request, map->dst) < 0) {
/*
* Not a real attr: might be a dynamic comparison.
*/
if ((map->dst->type == VPT_TYPE_ATTR) &&
- (map->dst->da->vendor == 0) &&
- radius_find_compare(map->dst->da)) {
- rhs_vp = pairalloc(request, map->dst->da);
- rad_assert(rhs_vp != NULL);
- if (!pairparsevalue(rhs_vp, rhs)) {
+ (map->dst->vpt_da->vendor == 0) &&
+ radius_find_compare(map->dst->vpt_da)) {
+ rhs_vp = pairalloc(request, map->dst->vpt_da);
+ rad_assert(rhs_vp != NULL);
+ if (pairparsevalue(rhs_vp, rhs, 0) < 0) {
talloc_free(rhs);
EVAL_DEBUG("FAIL %d", __LINE__);
return -1;
/*
* Get VP for RHS
*/
- rhs_vp = pairalloc(request, map->dst->da);
+ rhs_vp = pairalloc(request, map->dst->vpt_da);
rad_assert(rhs_vp != NULL);
- if (!pairparsevalue(rhs_vp, rhs)) {
+ if (pairparsevalue(rhs_vp, rhs, 0) < 0) {
talloc_free(rhs);
pairfree(&rhs_vp);
EVAL_DEBUG("FAIL %d", __LINE__);
EVAL_DEBUG("FAIL %d", __LINE__);
return -1;
}
+ rad_assert(lhs != NULL);
EVAL_DEBUG("LHS is %s", lhs);
/*
- * Compile the RHS to a regex, and do regex stuff
- */
- if (map->src->type == VPT_TYPE_REGEX) {
- return do_regex(request, lhs, rhs, c->regex_i);
- }
-
- /*
* Loop over the string, doing comparisons
*/
if (all_digits(lhs) && all_digits(rhs)) {
}
} else {
+ rad_assert(lhs != NULL);
+ rad_assert(rhs != NULL);
+
rcode = strcmp(lhs, rhs);
talloc_free(lhs);
talloc_free(rhs);
fr_cond_t const *c)
{
int rcode = -1;
+#ifdef WITH_EVAL_DEBUG
+ char buffer[1024];
+
+ fr_cond_sprint(buffer, sizeof(buffer), c);
+ EVAL_DEBUG("%s", buffer);
+#endif
while (c) {
switch (c->type) {
* only paircopy() those attributes that we're really going to
* use.
*/
-void radius_pairmove(REQUEST *request, VALUE_PAIR **to, VALUE_PAIR *from)
+void radius_pairmove(REQUEST *request, VALUE_PAIR **to, VALUE_PAIR *from, bool do_xlat)
{
int i, j, count, from_count, to_count, tailto;
vp_cursor_t cursor;
int *edited = NULL;
REQUEST *fixup = NULL;
+ if (!request) return;
+
/*
* Set up arrays for editing, to remove some of the
* O(N^2) dependencies. This also makes it easier to
* the matching attributes are deleted.
*/
count = 0;
- for (vp = paircursor(&cursor, &from); vp; vp = pairnext(&cursor)) count++;
+ for (vp = fr_cursor_init(&cursor, &from); vp; vp = fr_cursor_next(&cursor)) count++;
from_list = rad_malloc(sizeof(*from_list) * count);
- for (vp = paircursor(&cursor, to); vp; vp = pairnext(&cursor)) count++;
+ for (vp = fr_cursor_init(&cursor, to); vp; vp = fr_cursor_next(&cursor)) count++;
to_list = rad_malloc(sizeof(*to_list) * count);
/*
RDEBUG4("::: Examining %s", from_list[i]->da->name);
+ if (do_xlat) radius_xlat_do(request, from_list[i]);
+
/*
* Attribute should be appended, OR the "to" list
* is empty, and we're supposed to replace or
*last = vp;
last = &(*last)->next;
- (void) talloc_steal(request, vp);
}
- rad_assert(request != NULL);
rad_assert(request->packet != NULL);
free(to_list);
#include <fcntl.h>
#include <ctype.h>
-#include <signal.h>
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
* @param shell_escape values before passing them as arguments.
* @return PID of the child process, -1 on error.
*/
-pid_t radius_start_program(char const *cmd, REQUEST *request,
- int exec_wait,
- int *input_fd,
- int *output_fd,
- VALUE_PAIR *input_pairs,
- int shell_escape)
+pid_t radius_start_program(char const *cmd, REQUEST *request, bool exec_wait,
+ int *input_fd, int *output_fd,
+ VALUE_PAIR *input_pairs, bool shell_escape)
{
#ifndef __MINGW32__
char *p;
char argv_buf[4096];
#define MAX_ENVP 1024
char *envp[MAX_ENVP];
+ int envlen = 0;
argc = rad_expand_xlat(request, cmd, MAX_ARGV, argv, true, sizeof(argv_buf), argv_buf);
if (argc <= 0) {
if (exec_wait) {
if (input_fd) {
if (pipe(to_child) != 0) {
- RDEBUG("Couldn't open pipe to child: %s", strerror(errno));
+ RDEBUG("Couldn't open pipe to child: %s", fr_syserror(errno));
return -1;
}
}
if (output_fd) {
if (pipe(from_child) != 0) {
- RDEBUG("Couldn't open pipe from child: %s", strerror(errno));
+ RDEBUG("Couldn't open pipe from child: %s", fr_syserror(errno));
/* safe because these either need closing or are == -1 */
close(to_child[0]);
close(to_child[1]);
if (input_pairs) {
vp_cursor_t cursor;
- int envlen;
char buffer[1024];
/*
* hold mutexes. They might be locked when we fork,
* and will remain locked in the child.
*/
- envlen = 0;
-
- for (vp = paircursor(&cursor, &input_pairs); vp; vp = pairnext(&cursor)) {
+ for (vp = fr_cursor_init(&cursor, &input_pairs); vp; vp = fr_cursor_next(&cursor)) {
/*
* Hmm... maybe we shouldn't pass the
* user's password in an environment
}
n = strlen(buffer);
- vp_prints_value(buffer+n, sizeof(buffer) - n, vp, shell_escape ? '"' : 0);
+ vp_prints_value(buffer + n, sizeof(buffer) - n, vp, shell_escape ? '"' : 0);
envp[envlen++] = strdup(buffer);
* Don't add too many attributes.
*/
if (envlen == (MAX_ENVP - 1)) break;
+
+ /*
+ * NULL terminate for execve
+ */
+ envp[envlen] = NULL;
}
- envp[envlen] = NULL;
}
if (exec_wait) {
*/
devnull = open("/dev/null", O_RDWR);
if (devnull < 0) {
- RDEBUG("Failed opening /dev/null: %s\n", strerror(errno));
+ RDEBUG("Failed opening /dev/null: %s\n", fr_syserror(errno));
/*
* Where the status code is interpreted as a module rcode
* has created them.
*/
if (exec_wait) {
-
if (input_fd) {
close(to_child[1]);
dup2(to_child[0], STDIN_FILENO);
* I swear the signature for execve is wrong and should take 'char const * const argv[]'.
*/
execve(argv[0], argv, envp);
- printf("Failed to execute \"%s\": %s", argv[0], strerror(errno)); /* fork output will be captured */
+ printf("Failed to execute \"%s\": %s", argv[0], fr_syserror(errno)); /* fork output will be captured */
/*
* Where the status code is interpreted as a module rcode
/*
* Free child environment variables
*/
- for (i = 0; envp[i] != NULL; i++) {
+ for (i = 0; i < envlen; i++) {
free(envp[i]);
}
* Parent process.
*/
if (pid < 0) {
- RDEBUG("Couldn't fork %s: %s", argv[0], strerror(errno));
+ RDEBUG("Couldn't fork %s: %s", argv[0], fr_syserror(errno));
if (exec_wait) {
/* safe because these either need closing or are == -1 */
close(to_child[0]);
close(to_child[1]);
close(from_child[0]);
- close(from_child[0]);
+ close(from_child[1]);
}
return -1;
}
int status;
struct timeval start;
#ifdef O_NONBLOCK
- int nonblock = true;
+ bool nonblock = true;
#endif
#ifdef O_NONBLOCK
if (left <= 0) break;
}
#endif /* __MINGW32__ */
+
+ /* Strip trailing new lines */
+ while ((done > 0) && (answer[done - 1] == '\n')) {
+ answer[--done] = '\0';
+ }
+
return done;
}
/** Execute a program.
*
- * @param[in] request Current request.
+ * @param[in] request Current request (may be NULL).
* @param[in] cmd Command to execute. This is parsed into argv[] parts, then each individual argv part
* is xlat'ed.
* @param[in] exec_wait set to 1 if you want to read from or write to child.
pid_t pid;
int from_child;
#ifndef __MINGW32__
- VALUE_PAIR *vp;
char *p;
pid_t child_pid;
int comma = 0;
- int status;
- int n, done;
+ int status, ret = 0;
+ ssize_t len;
char answer[4096];
#endif
- RDEBUG2("Executing: \"%s\"", cmd);
+
+ DEBUG2("Executing: %s:", cmd);
if (user_msg) *user_msg = '\0';
}
#ifndef __MINGW32__
- done = radius_readfrom_program(request, from_child, pid, timeout, answer, sizeof(answer));
- if (done < 0) {
+ len = radius_readfrom_program(request, from_child, pid, timeout, answer, sizeof(answer));
+ if (len < 0) {
/*
- * failure - radius_readfrom_program will
- * have called close(from_child) for us
+ * Failure - radius_readfrom_program will
+ * have called close(from_child) for us
*/
DEBUG("Failed to read from child output");
return -1;
}
- answer[done] = '\0';
+ answer[len] = '\0';
/*
* Make sure that the writer can't block while writing to
*/
close(from_child);
+ if (len == 0) {
+ goto wait;
+ }
+
/*
* Parse the output, if any.
*/
- if (done) {
- n = T_OP_INVALID;
- if (output_pairs) {
- /*
- * For backwards compatibility, first check
- * for plain text (user_msg).
- */
- vp = NULL;
- n = userparse(request, answer, &vp);
- if (vp) {
- pairfree(&vp);
- }
- }
-
- if (n == T_OP_INVALID) {
- if (user_msg) {
- strlcpy(user_msg, answer, msg_len);
+ if (output_pairs) {
+ /*
+ * HACK: Replace '\n' with ',' so that
+ * userparse() can parse the buffer in
+ * one go (the proper way would be to
+ * fix userparse(), but oh well).
+ */
+ for (p = answer; *p; p++) {
+ if (*p == '\n') {
+ *p = comma ? ' ' : ',';
+ p++;
+ comma = 0;
}
- } else {
- /*
- * HACK: Replace '\n' with ',' so that
- * userparse() can parse the buffer in
- * one go (the proper way would be to
- * fix userparse(), but oh well).
- */
- for (p = answer; *p; p++) {
- if (*p == '\n') {
- *p = comma ? ' ' : ',';
- p++;
- comma = 0;
- }
- if (*p == ',') comma++;
+ if (*p == ',') {
+ comma++;
}
+ }
- /*
- * Replace any trailing comma by a NUL.
- */
- if (answer[strlen(answer) - 1] == ',') {
- answer[strlen(answer) - 1] = '\0';
- }
+ /*
+ * Replace any trailing comma by a NUL.
+ */
+ if (answer[len - 1] == ',') {
+ answer[--len] = '\0';
+ }
- if (userparse(request, answer, &vp) == T_OP_INVALID) {
- REDEBUG("Unparsable reply from '%s'", cmd);
+ if (userparse(request, answer, output_pairs) == T_OP_INVALID) {
+ ERROR("Failed parsing output from: %s: %s", cmd, fr_strerror());
+ strlcpy(user_msg, answer, len);
+ ret = -1;
+ }
+ /*
+ * We've not been told to extract output pairs,
+ * just copy the programs output to the user_msg
+ * buffer.
+ */
- return -1;
- } else {
- /*
- * Tell the caller about the value
- * pairs.
- */
- *output_pairs = vp;
- }
- } /* else the answer was a set of VP's, not a text message */
- } /* else we didn't read anything from the child */
+ } else if (user_msg) {
+ strlcpy(user_msg, answer, msg_len);
+ }
/*
* Call rad_waitpid (should map to waitpid on non-threaded
* or single-server systems).
*/
+wait:
child_pid = rad_waitpid(pid, &status);
if (child_pid == 0) {
- REDEBUG("Timeout waiting for child");
+ ERROR("Timeout waiting for child");
return -2;
}
if (child_pid == pid) {
if (WIFEXITED(status)) {
status = WEXITSTATUS(status);
+ if ((status != 0) || (ret < 0)) {
+ ERROR("Program returned code (%d) and output '%s'", status, answer);
+ } else {
+ ERROR("Program returned code (%d) and output '%s'", status, answer);
+ }
- RDEBUG("Program returned code (%d): %s", status, answer);
-
- return status;
+ return ret < 0 ? ret : status;
}
}
- REDEBUG("Abnormal child exit: %s", strerror(errno));
+ ERROR("Abnormal child exit: %s", fr_syserror(errno));
#endif /* __MINGW32__ */
return -1;
if (!complain)
return -1;
ERROR("Couldn't open %s for reading: %s",
- file, strerror(errno));
+ file, fr_syserror(errno));
return -1;
}
}
ptr = buffer;
- getword(&ptr, entry, sizeof(entry));
+ getword(&ptr, entry, sizeof(entry), false);
/*
* Include another file if we see
p = newfile + strlen(newfile);
*p = FR_DIR_SEP;
}
- getword(&ptr, p + 1,
- sizeof(newfile) - 1 - (p - newfile));
+ getword(&ptr, p + 1, sizeof(newfile) - 1 - (p - newfile), false);
} else {
- getword(&ptr, newfile,
- sizeof(newfile));
+ getword(&ptr, newfile, sizeof(newfile), false);
}
t = NULL;
if (pairlist_read(ctx, newfile, &t, 0) != 0) {
pairlist_free(&pl);
ERROR("%s[%d]: Could not open included file %s: %s",
- file, lineno, newfile, strerror(errno));
+ file, lineno, newfile, fr_syserror(errno));
fclose(fp);
return -1;
}
check_tmp = NULL;
reply_tmp = NULL;
- t->name = talloc_strdup(t, entry);
+ t->name = talloc_typed_strdup(t, entry);
*last = t;
last = &(t->next);
#include <freeradius-devel/rad_assert.h>
#include <freeradius-devel/process.h>
#include <freeradius-devel/protocol.h>
+#include <freeradius-devel/modpriv.h>
#include <freeradius-devel/detail.h>
if (!fmt || !out || (outlen < 1)) return 0;
- if (!request || !request->listener) {
+ if (!request->listener) {
RWDEBUG("No listener associated with this request");
*out = '\0';
return 0;
* Find a per-socket client.
*/
RADCLIENT *client_listener_find(rad_listen_t *listener,
- fr_ipaddr_t const *ipaddr, int src_port)
+ fr_ipaddr_t const *ipaddr, uint16_t src_port)
{
#ifdef WITH_DYNAMIC_CLIENTS
int rcode;
request->number = 0;
request->priority = listener->type;
request->server = client->client_server;
- request->root = &mainconfig;
+ request->root = &main_config;
/*
* Run a fake request through the given virtual server.
switch (rcode) {
case RLM_MODULE_OK:
case RLM_MODULE_UPDATED:
- request->reply->code = PW_AUTHENTICATION_ACK;
+ request->reply->code = PW_CODE_AUTHENTICATION_ACK;
break;
case RLM_MODULE_FAIL:
default:
case RLM_MODULE_REJECT:
- request->reply->code = PW_AUTHENTICATION_REJECT;
+ request->reply->code = PW_CODE_AUTHENTICATION_REJECT;
break;
}
break;
switch (rcode) {
case RLM_MODULE_OK:
case RLM_MODULE_UPDATED:
- request->reply->code = PW_ACCOUNTING_RESPONSE;
+ request->reply->code = PW_CODE_ACCOUNTING_RESPONSE;
break;
default:
switch (rcode) {
case RLM_MODULE_OK:
case RLM_MODULE_UPDATED:
- request->reply->code = PW_COA_ACK;
+ request->reply->code = PW_CODE_COA_ACK;
break;
default:
sock->packet->src_port = sock->other_port;
sock->packet->dst_ipaddr = sock->my_ipaddr;
sock->packet->dst_port = sock->my_port;
+ sock->packet->proto = sock->proto;
}
/*
if (rcode == -1) { /* error reading packet */
char buffer[256];
- ERROR("Invalid packet from %s port %d: closing socket",
+ ERROR("Invalid packet from %s port %d, closing socket: %s",
ip_ntoh(&packet->src_ipaddr, buffer, sizeof(buffer)),
- packet->src_port);
+ packet->src_port, fr_strerror());
}
if (rcode < 0) { /* error or connection reset */
* Tell the event handler that an FD has disappeared.
*/
DEBUG("Client has closed connection");
- event_new_fd(listener);
+ radius_update_listener(listener);
/*
* Do NOT free the listener here. It's in use by
* Some sanity checks, based on the packet code.
*/
switch(packet->code) {
- case PW_AUTHENTICATION_REQUEST:
+ case PW_CODE_AUTHENTICATION_REQUEST:
if (listener->type != RAD_LISTEN_AUTH) goto bad_packet;
FR_STATS_INC(auth, total_requests);
fun = rad_authenticate;
break;
#ifdef WITH_ACCOUNTING
- case PW_ACCOUNTING_REQUEST:
+ case PW_CODE_ACCOUNTING_REQUEST:
if (listener->type != RAD_LISTEN_ACCT) goto bad_packet;
FR_STATS_INC(acct, total_requests);
fun = rad_accounting;
break;
#endif
- case PW_STATUS_SERVER:
- if (!mainconfig.status_server) {
+ case PW_CODE_STATUS_SERVER:
+ if (!main_config.status_server) {
FR_STATS_INC(auth, total_unknown_types);
- WDEBUG("Ignoring Status-Server request due to security configuration");
+ WARN("Ignoring Status-Server request due to security configuration");
rad_free(&sock->packet);
return 0;
}
static int dual_tcp_accept(rad_listen_t *listener)
{
- int newfd, src_port;
+ int newfd;
+ uint16_t src_port;
rad_listen_t *this;
socklen_t salen;
struct sockaddr_storage src;
salen = sizeof(src);
- DEBUG2(" ... new connection request on TCP socket.");
+ DEBUG2(" ... new connection request on TCP socket");
newfd = accept(listener->fd, (struct sockaddr *) &src, &salen);
if (newfd < 0) {
}
#endif
- DEBUG2(" ... failed to accept connection.");
+ DEBUG2(" ... failed to accept connection");
return -1;
}
if (!fr_sockaddr2ipaddr(&src, salen, &src_ipaddr, &src_port)) {
close(newfd);
- DEBUG2(" ... unknown address family.");
+ DEBUG2(" ... unknown address family");
return 0;
}
* Tell the event loop that we have a new FD.
* This can be called from a child thread...
*/
- event_new_fd(this);
+ radius_update_listener(this);
return 0;
}
/*
* Ensure that we always keep the correct counters.
*/
-#ifdef WITH_TLS
+#ifdef WITH_TCP
static void common_socket_free(rad_listen_t *this)
{
listen_socket_t *sock = this->data;
if (sock->proto != IPPROTO_TCP) return;
- if (!sock->parent) return;
-
/*
* Decrement the number of connections.
*/
- if (sock->parent->limit.num_connections > 0) {
+ if (sock->parent && (sock->parent->limit.num_connections > 0)) {
sock->parent->limit.num_connections--;
}
- if (sock->client->limit.num_connections > 0) {
+ if (sock->client && sock->client->limit.num_connections > 0) {
sock->client->limit.num_connections--;
}
+ if (sock->home && sock->home->limit.num_connections > 0) {
+ sock->home->limit.num_connections--;
+ }
}
#else
static void common_socket_free(UNUSED rad_listen_t *this)
extern bool check_config; /* radiusd.c */
static CONF_PARSER performance_config[] = {
- { "skip_duplicate_checks", PW_TYPE_BOOLEAN,
- offsetof(rad_listen_t, nodup), NULL, NULL },
+ { "skip_duplicate_checks", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rad_listen_t, nodup), NULL },
- { "synchronous", PW_TYPE_BOOLEAN,
- offsetof(rad_listen_t, synchronous), NULL, NULL },
+ { "synchronous", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rad_listen_t, synchronous), NULL },
- { "workers", PW_TYPE_INTEGER,
- offsetof(rad_listen_t, workers), NULL, NULL },
+ { "workers", FR_CONF_OFFSET(PW_TYPE_INTEGER, rad_listen_t, workers), NULL },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
static CONF_PARSER limit_config[] = {
- { "max_pps", PW_TYPE_INTEGER,
- offsetof(listen_socket_t, max_rate), NULL, NULL },
+ { "max_pps", FR_CONF_OFFSET(PW_TYPE_INTEGER, listen_socket_t, max_rate), NULL },
#ifdef WITH_TCP
- { "max_connections", PW_TYPE_INTEGER,
- offsetof(listen_socket_t, limit.max_connections), NULL, "16" },
-
- { "lifetime", PW_TYPE_INTEGER,
- offsetof(listen_socket_t, limit.lifetime), NULL, "0" },
-
- { "idle_timeout", PW_TYPE_INTEGER,
- offsetof(listen_socket_t, limit.idle_timeout), NULL, "30" },
+ { "max_connections", FR_CONF_OFFSET(PW_TYPE_INTEGER, listen_socket_t, limit.max_connections), "16" },
+ { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, listen_socket_t, limit.lifetime), "0" },
+ { "idle_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, listen_socket_t, limit.idle_timeout), STRINGIFY(30) },
#endif
{ NULL, -1, 0, NULL, NULL } /* end the list */
int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
{
int rcode;
- int listen_port;
+ uint16_t listen_port;
fr_ipaddr_t ipaddr;
listen_socket_t *sock = this->data;
- char *section_name = NULL;
+ char const *section_name = NULL;
CONF_SECTION *client_cs, *parentcs;
CONF_SECTION *subcs;
*/
memset(&ipaddr, 0, sizeof(ipaddr));
ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_NONE);
- rcode = cf_item_parse(cs, "ipaddr", PW_TYPE_IPADDR,
- &ipaddr.ipaddr.ip4addr, NULL);
- if (rcode < 0) return -1;
-
- if (rcode == 0) { /* successfully parsed IPv4 */
- ipaddr.af = AF_INET;
-
- } else { /* maybe IPv6? */
- rcode = cf_item_parse(cs, "ipv6addr", PW_TYPE_IPV6ADDR,
- &ipaddr.ipaddr.ip6addr, NULL);
- if (rcode < 0) return -1;
- if (rcode == 1) {
- cf_log_err_cs(cs,
- "No address specified in listen section");
- return -1;
- }
- ipaddr.af = AF_INET6;
+ rcode = cf_item_parse(cs, "ipaddr", FR_ITEM_POINTER(PW_TYPE_IP_ADDR, &ipaddr), NULL);
+ if (rcode < 0) return -1;
+ if (rcode != 0) rcode = cf_item_parse(cs, "ipv4addr", FR_ITEM_POINTER(PW_TYPE_IPV4_ADDR, &ipaddr), NULL);
+ if (rcode < 0) return -1;
+ if (rcode != 0) rcode = cf_item_parse(cs, "ipv6addr", FR_ITEM_POINTER(PW_TYPE_IPV6_ADDR, &ipaddr), NULL);
+ if (rcode < 0) return -1;
+ if (rcode != 0) {
+ cf_log_err_cs(cs, "No address specified in listen section");
+ return -1;
}
- rcode = cf_item_parse(cs, "port", PW_TYPE_INTEGER,
- &listen_port, "0");
+ rcode = cf_item_parse(cs, "port", FR_ITEM_POINTER(PW_TYPE_SHORT, &listen_port), "0");
if (rcode < 0) return -1;
- if ((listen_port < 0) || (listen_port > 65535)) {
- cf_log_err_cs(cs,
- "Invalid value for \"port\"");
- return -1;
- }
-
sock->proto = IPPROTO_UDP;
if (cf_pair_find(cs, "proto")) {
#ifndef WITH_TCP
cf_log_err_cs(cs,
- "System does not support the TCP protocol. Delete this line from the configuration file.");
+ "System does not support the TCP protocol. Delete this line from the configuration file");
return -1;
#else
- char *proto = NULL;
+ char const *proto = NULL;
#ifdef WITH_TLS
CONF_SECTION *tls;
#endif
- rcode = cf_item_parse(cs, "proto", PW_TYPE_STRING_PTR,
- &proto, "udp");
+ rcode = cf_item_parse(cs, "proto", FR_ITEM_POINTER(PW_TYPE_STRING, &proto), "udp");
if (rcode < 0) return -1;
if (strcmp(proto, "udp") == 0) {
#ifdef WITH_TLS
tls = cf_section_sub_find(cs, "tls");
- /*
- * Don't allow TLS configurations for UDP sockets.
- */
- if (sock->proto != IPPROTO_TCP) {
- cf_log_err_cs(cs,
- "TLS transport is not available for UDP sockets.");
- return -1;
- }
-
if (tls) {
/*
- * FIXME: Make this better.
+ * Don't allow TLS configurations for UDP sockets.
+ */
+ if (sock->proto != IPPROTO_TCP) {
+ cf_log_err_cs(cs,
+ "TLS transport is not available for UDP sockets");
+ return -1;
+ }
+
+ /*
+ * If unset, set to default.
*/
- if (listen_port == 0) listen_port = 2083;
+ if (listen_port == 0) listen_port = PW_RADIUS_TLS_PORT;
this->tls = tls_server_conf_parse(tls);
if (!this->tls) {
*/
if (cf_section_sub_find(cs, "tls")) {
cf_log_err_cs(cs,
- "TLS transport is not available in this executable.");
+ "TLS transport is not available in this executable");
return -1;
}
#endif /* WITH_TLS */
*/
} else if (cf_section_sub_find(cs, "tls")) {
cf_log_err_cs(cs,
- "TLS transport is not available in this \"listen\" section.");
+ "TLS transport is not available in this \"listen\" section");
return -1;
}
#ifdef WITH_PROXY
if (check_config) {
/*
- * Until there is a side effects free way of forwarding a
- * request to another virtual server, this check is invalid,
- * and should be left disabled.
- */
+ * Until there is a side effects free way of forwarding a
+ * request to another virtual server, this check is invalid,
+ * and should be left disabled.
+ */
#if 0
if (home_server_find(&sock->my_ipaddr, sock->my_port, sock->proto)) {
char buffer[128];
- EDEBUG("We have been asked to listen on %s port %d, which is also listed as a "
+ ERROR("We have been asked to listen on %s port %d, which is also listed as a "
"home server. This can create a proxy loop",
ip_ntoh(&sock->my_ipaddr, buffer, sizeof(buffer)), sock->my_port);
return -1;
if (cf_pair_find(cs, "broadcast")) {
#ifndef SO_BROADCAST
cf_log_err_cs(cs,
- "System does not support broadcast sockets. Delete this line from the configuration file.");
+ "System does not support broadcast sockets. Delete this line from the configuration file");
return -1;
#else
char const *value;
if (this->type != RAD_LISTEN_DHCP) {
cf_log_err_cp(cp,
- "Broadcast can only be set for DHCP listeners. Delete this line from the configuration file.");
+ "Broadcast can only be set for DHCP listeners. Delete this line from the configuration file");
return -1;
}
*/
client_cs = NULL;
parentcs = cf_top_section(cs);
- rcode = cf_item_parse(cs, "clients", PW_TYPE_STRING_PTR,
- §ion_name, NULL);
+ rcode = cf_item_parse(cs, "clients", FR_ITEM_POINTER(PW_TYPE_STRING, §ion_name), NULL);
if (rcode < 0) return -1; /* bad string */
if (rcode == 0) {
/*
* Explicit list given: use it.
*/
- client_cs = cf_section_sub_find_name2(parentcs,
- "clients",
- section_name);
+ client_cs = cf_section_sub_find_name2(parentcs, "clients", section_name);
if (!client_cs) {
client_cs = cf_section_find(section_name);
}
rad_assert(request->listener == listener);
rad_assert(listener->send == auth_socket_send);
+ if (request->reply->code == 0) return 0;
+
#ifdef WITH_UDPFROMTO
/*
* Overwrite the src ip address on the outbound packet
static int stats_socket_recv(rad_listen_t *listener)
{
ssize_t rcode;
- int code, src_port;
+ int code;
+ uint16_t src_port;
RADIUS_PACKET *packet;
RADCLIENT *client = NULL;
fr_ipaddr_t src_ipaddr;
/*
* We only understand Status-Server on this socket.
*/
- if (code != PW_STATUS_SERVER) {
+ if (code != PW_CODE_STATUS_SERVER) {
DEBUG("Ignoring packet code %d sent to Status-Server port",
code);
rad_recv_discard(listener->fd);
static int auth_socket_recv(rad_listen_t *listener)
{
ssize_t rcode;
- int code, src_port;
+ int code;
+ uint16_t src_port;
RADIUS_PACKET *packet;
RAD_REQUEST_FUNP fun = NULL;
RADCLIENT *client = NULL;
* Some sanity checks, based on the packet code.
*/
switch(code) {
- case PW_AUTHENTICATION_REQUEST:
+ case PW_CODE_AUTHENTICATION_REQUEST:
fun = rad_authenticate;
break;
- case PW_STATUS_SERVER:
- if (!mainconfig.status_server) {
+ case PW_CODE_STATUS_SERVER:
+ if (!main_config.status_server) {
rad_recv_discard(listener->fd);
FR_STATS_INC(auth, total_unknown_types);
- WDEBUG("Ignoring Status-Server request due to security configuration");
+ WARN("Ignoring Status-Server request due to security configuration");
return 0;
}
fun = rad_status_server;
static int acct_socket_recv(rad_listen_t *listener)
{
ssize_t rcode;
- int code, src_port;
+ int code;
+ uint16_t src_port;
RADIUS_PACKET *packet;
RAD_REQUEST_FUNP fun = NULL;
RADCLIENT *client = NULL;
* Some sanity checks, based on the packet code.
*/
switch(code) {
- case PW_ACCOUNTING_REQUEST:
+ case PW_CODE_ACCOUNTING_REQUEST:
fun = rad_accounting;
break;
- case PW_STATUS_SERVER:
- if (!mainconfig.status_server) {
+ case PW_CODE_STATUS_SERVER:
+ if (!main_config.status_server) {
rad_recv_discard(listener->fd);
FR_STATS_INC(acct, total_unknown_types);
- WDEBUG("Ignoring Status-Server request due to security configuration");
+ WARN("Ignoring Status-Server request due to security configuration");
return 0;
}
fun = rad_status_server;
* Get the correct response
*/
switch (request->packet->code) {
- case PW_COA_REQUEST:
- ack = PW_COA_ACK;
- nak = PW_COA_NAK;
+ case PW_CODE_COA_REQUEST:
+ ack = PW_CODE_COA_ACK;
+ nak = PW_CODE_COA_NAK;
break;
- case PW_DISCONNECT_REQUEST:
- ack = PW_DISCONNECT_ACK;
- nak = PW_DISCONNECT_NAK;
+ case PW_CODE_DISCONNECT_REQUEST:
+ ack = PW_CODE_DISCONNECT_ACK;
+ nak = PW_CODE_DISCONNECT_NAK;
break;
default: /* shouldn't happen */
* have a State attribute in it.
*/
vp = pairfind(request->packet->vps, PW_SERVICE_TYPE, 0, TAG_ANY);
- if (request->packet->code == PW_COA_REQUEST) {
+ if (request->packet->code == PW_CODE_COA_REQUEST) {
if (vp && (vp->vp_integer == 17)) {
vp = pairfind(request->packet->vps, PW_STATE, 0, TAG_ANY);
if (!vp || (vp->length == 0)) {
REDEBUG("CoA-Request with Service-Type = Authorize-Only MUST contain a State attribute");
- request->reply->code = PW_COA_NAK;
+ request->reply->code = PW_CODE_COA_NAK;
return RLM_MODULE_FAIL;
}
}
* RFC 5176, Section 3.2.
*/
REDEBUG("Disconnect-Request MUST NOT contain a Service-Type attribute");
- request->reply->code = PW_DISCONNECT_NAK;
+ request->reply->code = PW_CODE_DISCONNECT_NAK;
return RLM_MODULE_FAIL;
}
static int coa_socket_recv(rad_listen_t *listener)
{
ssize_t rcode;
- int code, src_port;
+ int code;
+ uint16_t src_port;
RADIUS_PACKET *packet;
RAD_REQUEST_FUNP fun = NULL;
RADCLIENT *client = NULL;
* Some sanity checks, based on the packet code.
*/
switch(code) {
- case PW_COA_REQUEST:
+ case PW_CODE_COA_REQUEST:
FR_STATS_INC(coa, total_requests);
fun = rad_coa_recv;
break;
- case PW_DISCONNECT_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
FR_STATS_INC(dsc, total_requests);
fun = rad_coa_recv;
break;
* FIXME: Client MIB updates?
*/
switch(packet->code) {
- case PW_AUTHENTICATION_ACK:
- case PW_ACCESS_CHALLENGE:
- case PW_AUTHENTICATION_REJECT:
+ case PW_CODE_AUTHENTICATION_ACK:
+ case PW_CODE_ACCESS_CHALLENGE:
+ case PW_CODE_AUTHENTICATION_REJECT:
break;
#ifdef WITH_ACCOUNTING
- case PW_ACCOUNTING_RESPONSE:
+ case PW_CODE_ACCOUNTING_RESPONSE:
break;
#endif
#ifdef WITH_COA
- case PW_DISCONNECT_ACK:
- case PW_DISCONNECT_NAK:
- case PW_COA_ACK:
- case PW_COA_NAK:
+ case PW_CODE_DISCONNECT_ACK:
+ case PW_CODE_DISCONNECT_NAK:
+ case PW_CODE_COA_ACK:
+ case PW_CODE_COA_NAK:
break;
#endif
packet = fr_tcp_recv(listener->fd, 0);
if (!packet) {
listener->status = RAD_LISTEN_STATUS_EOL;
- event_new_fd(listener);
+ radius_update_listener(listener);
return 0;
}
* FIXME: Client MIB updates?
*/
switch(packet->code) {
- case PW_AUTHENTICATION_ACK:
- case PW_ACCESS_CHALLENGE:
- case PW_AUTHENTICATION_REJECT:
+ case PW_CODE_AUTHENTICATION_ACK:
+ case PW_CODE_ACCESS_CHALLENGE:
+ case PW_CODE_AUTHENTICATION_REJECT:
break;
#ifdef WITH_ACCOUNTING
- case PW_ACCOUNTING_RESPONSE:
+ case PW_CODE_ACCOUNTING_RESPONSE:
break;
#endif
#endif
default:
- WDEBUG("Internal sanity check failed in binding to socket. Ignoring problem.");
+ WARN("Internal sanity check failed in binding to socket. Ignoring problem");
return -1;
}
}
this->print(this, buffer, sizeof(buffer));
- ERROR("Failed opening %s: %s", buffer, strerror(errno));
+ ERROR("Failed opening %s: %s", buffer, fr_syserror(errno));
return -1;
}
if (rcode >= 0) {
if (fcntl(this->fd, F_SETFD, rcode | FD_CLOEXEC) < 0) {
close(this->fd);
- ERROR("Failed setting close on exec: %s", strerror(errno));
+ ERROR("Failed setting close on exec: %s", fr_syserror(errno));
return -1;
}
}
if (rcode < 0) {
close(this->fd);
ERROR("Failed binding to interface %s: %s",
- sock->interface, strerror(errno));
+ sock->interface, fr_syserror(errno));
return -1;
} /* else it worked. */
#else
if (sock->my_ipaddr.scope == 0) {
close(this->fd);
ERROR("Failed finding interface %s: %s",
- sock->interface, strerror(errno));
+ sock->interface, fr_syserror(errno));
return -1;
}
} /* else scope was defined: we're OK. */
if (setsockopt(this->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
close(this->fd);
- ERROR("Failed to reuse address: %s", strerror(errno));
+ ERROR("Failed to reuse address: %s", fr_syserror(errno));
return -1;
}
}
*/
if (udpfromto_init(this->fd) != 0) {
ERROR("Failed initializing udpfromto: %s",
- strerror(errno));
+ fr_syserror(errno));
close(this->fd);
return -1;
}
if (setsockopt(this->fd, IPPROTO_IPV6, IPV6_V6ONLY,
(char *)&on, sizeof(on)) < 0) {
ERROR("Failed setting socket to IPv6 "
- "only: %s", strerror(errno));
+ "only: %s", fr_syserror(errno));
- close(this->fd);
+ close(this->fd);
return -1;
}
}
if (setsockopt(this->fd, IPPROTO_IP, IP_MTU_DISCOVER,
&flag, sizeof(flag)) < 0) {
ERROR("Failed disabling PMTU discovery: %s",
- strerror(errno));
+ fr_syserror(errno));
close(this->fd);
return -1;
if (setsockopt(this->fd, IPPROTO_IP, IP_DONTFRAG,
&flag, sizeof(flag)) < 0) {
ERROR("Failed setting don't fragment flag: %s",
- strerror(errno));
+ fr_syserror(errno));
close(this->fd);
return -1;
if (setsockopt(this->fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
ERROR("Can't set broadcast option: %s",
- strerror(errno));
+ fr_syserror(errno));
return -1;
}
}
* May be binding to priviledged ports.
*/
if (sock->my_port != 0) {
-#ifdef SO_REUSEADDR
- int on = 1;
-
- if (setsockopt(this->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
- ERROR("Can't set re-use address option: %s",
- strerror(errno));
- return -1;
- }
-#endif
-
fr_suid_up();
rcode = bind(this->fd, (struct sockaddr *) &salocal, salen);
fr_suid_down();
this->print(this, buffer, sizeof(buffer));
ERROR("Failed binding to %s: %s\n",
- buffer, strerror(errno));
+ buffer, fr_syserror(errno));
return -1;
}
if (getsockname(this->fd, (struct sockaddr *) &src,
&sizeof_src) < 0) {
ERROR("Failed getting socket name: %s",
- strerror(errno));
+ fr_syserror(errno));
return -1;
}
#ifdef WITH_TCP
if (sock->proto == IPPROTO_TCP) {
/*
- * Allow a backlog of 8 listeners
+ * If there are hard-coded worker threads, OR
+ * it's a TLS connection, it's blocking.
+ *
+ * Otherwise, they're non-blocking.
*/
- if (listen(this->fd, 8) < 0) {
- close(this->fd);
- ERROR("Failed in listen(): %s", strerror(errno));
- return -1;
+ if (!this->workers
+#ifdef WITH_PROXY
+#ifdef WITH_TLS
+ && (this->type == RAD_LISTEN_PROXY) && !this->tls
+#endif
+#endif
+ ) {
+ if (fr_nonblock(this->fd) < 0) {
+ close(this->fd);
+ ERROR("Failed setting non-blocking on socket: %s",
+ fr_syserror(errno));
+ return -1;
+ }
}
/*
- * If there are hard-coded worker threads, they're blocking.
- *
- * Otherwise, they're non-blocking.
+ * Allow a backlog of 8 listeners, but only for incoming interfaces.
*/
- if (!this->workers && fr_nonblock(this->fd) < 0) {
+#ifdef WITH_PROXY
+ if (this->type != RAD_LISTEN_PROXY)
+#endif
+ if (listen(this->fd, 8) < 0) {
close(this->fd);
- ERROR("Failed setting non-blocking on socket: %s",
- strerror(errno));
+ ERROR("Failed in listen(): %s", fr_syserror(errno));
return -1;
}
}
) {
listen_socket_t *sock = this->data;
-#ifdef WITH_TLS
- if (sock->request) {
-# ifdef HAVE_PTHREAD_H
- pthread_mutex_destroy(&(sock->mutex));
-# endif
- request_free(&sock->request);
- sock->packet = NULL;
+ rad_free(&sock->packet);
+
+ rad_assert(sock->ev == NULL);
+#ifdef WITH_TLS
+ /*
+ * Note that we do NOT free this->tls, as the
+ * pointer is parented by its CONF_SECTION. It
+ * may be used by multiple listeners.
+ */
+ if (this->tls) {
if (sock->ssn) session_free(sock->ssn);
request_free(&sock->request);
- } else
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_destroy(&(sock->mutex));
#endif
- rad_free(&sock->packet);
+ }
+#endif /* WITH_TLS */
}
#endif /* WITH_TCP */
* Not thread-safe, but all calls to it are protected by the
* proxy mutex in event.c
*/
-rad_listen_t *proxy_new_listener(home_server *home, int src_port)
+rad_listen_t *proxy_new_listener(home_server_t *home, uint16_t src_port)
{
+ time_t now;
rad_listen_t *this;
listen_socket_t *sock;
char buffer[256];
if (!home) return NULL;
+ rad_assert(home->server == NULL); /* we only open real sockets */
+
if ((home->limit.max_connections > 0) &&
(home->limit.num_connections >= home->limit.max_connections)) {
- WDEBUG("Home server has too many open connections (%d)",
- home->limit.max_connections);
+ RATE_LIMIT(INFO("Home server %s has too many open connections (%d)",
+ home->name, home->limit.max_connections));
+ return NULL;
+ }
+
+ now = time(NULL);
+ if (home->last_failed_open == now) {
+ WARN("Suppressing attempt to open socket to 'down' home server");
return NULL;
}
- this = listen_alloc(mainconfig.config, RAD_LISTEN_PROXY);
+ this = listen_alloc(main_config.config, RAD_LISTEN_PROXY);
sock = this->data;
sock->other_ipaddr = home->ipaddr;
sock->my_port = src_port;
sock->proto = home->proto;
+ /*
+ * For error messages.
+ */
+ this->print(this, buffer, sizeof(buffer));
+
if (debug_flag >= 2) {
- this->print(this, buffer, sizeof(buffer));
- DEBUG("Opening new %s", buffer);
+ DEBUG("Opening new proxy socket '%s'", buffer);
}
#ifdef WITH_TCP
- sock->opened = sock->last_packet = time(NULL);
+ sock->opened = sock->last_packet = now;
if (home->proto == IPPROTO_TCP) {
this->recv = proxy_socket_tcp_recv;
*/
this->fd = fr_tcp_client_socket(&home->src_ipaddr,
&home->ipaddr, home->port);
-#ifdef WITH_TLS
- if (home->tls) {
- DEBUG("Trying SSL to port %d\n", home->port);
- sock->ssn = tls_new_client_session(home->tls, this->fd);
- if (!sock->ssn) {
- listen_free(&this);
- return NULL;
- }
-
- this->recv = proxy_tls_recv;
- this->send = proxy_tls_send;
- }
-#endif
} else
#endif
this->fd = fr_socket(&home->src_ipaddr, src_port);
if (this->fd < 0) {
this->print(this, buffer,sizeof(buffer));
- DEBUG("Failed opening client socket ::%s:: : %s",
+ ERROR("Failed opening proxy socket '%s' : %s",
buffer, fr_strerror());
+ home->last_failed_open = now;
listen_free(&this);
return NULL;
}
+
+#ifdef WITH_TCP
+#ifdef WITH_TLS
+ if ((home->proto == IPPROTO_TCP) && home->tls) {
+ DEBUG("Trying SSL to port %d\n", home->port);
+ sock->ssn = tls_new_client_session(home->tls, this->fd);
+ if (!sock->ssn) {
+ ERROR("Failed starting SSL to '%s'", buffer);
+ home->last_failed_open = now;
+ listen_free(&this);
+ return NULL;
+ }
+
+ this->recv = proxy_tls_recv;
+ this->send = proxy_tls_send;
+ }
+#endif
+#endif
/*
* Figure out which port we were bound to.
*/
memset(&src, 0, sizeof_src);
if (getsockname(this->fd, (struct sockaddr *) &src,
&sizeof_src) < 0) {
- ERROR("Failed getting socket name: %s",
- strerror(errno));
+ ERROR("Failed getting socket name for '%s': %s",
+ buffer, fr_syserror(errno));
+ home->last_failed_open = now;
listen_free(&this);
return NULL;
}
if (!fr_sockaddr2ipaddr(&src, sizeof_src,
&sock->my_ipaddr, &sock->my_port)) {
- ERROR("Socket has unsupported address family");
+ ERROR("Socket has unsupported address family for '%s'", buffer);
+ home->last_failed_open = now;
listen_free(&this);
return NULL;
}
}
+ home->limit.num_connections++;
+
return this;
}
#endif
-
static const FR_NAME_NUMBER listen_compare[] = {
#ifdef WITH_STATS
{ "status", RAD_LISTEN_NONE },
{ NULL, 0 },
};
+static int _free_proto_handle(lt_dlhandle *handle)
+{
+ dlclose(*handle);
+ return 0;
+}
static rad_listen_t *listen_parse(CONF_SECTION *cs, char const *server)
{
int type, rcode;
- char *listen_type;
+ char const *listen_type;
rad_listen_t *this;
CONF_PAIR *cp;
char const *value;
handle = lt_dlopenext(buffer);
if (handle) {
fr_protocol_t *proto;
+ lt_dlhandle *marker;
proto = dlsym(handle, buffer);
if (!proto) {
memcpy(&master_listen[type], proto, sizeof(*proto));
/*
- * And throw away the handle.
- * @todo: fix it later
+ * Ensure handle gets closed if config section gets freed
*/
+ marker = talloc(cs, lt_dlhandle);
+ *marker = handle;
+ talloc_set_destructor(marker, _free_proto_handle);
if (master_listen[type].magic != RLM_MODULE_INIT) {
ERROR("Failed to load protocol '%s' due to internal sanity check problem",
cf_log_info(cs, "listen {");
listen_type = NULL;
- rcode = cf_item_parse(cs, "type", PW_TYPE_STRING_PTR,
- &listen_type, "");
+ rcode = cf_item_parse(cs, "type", FR_ITEM_POINTER(PW_TYPE_STRING, &listen_type), "");
if (rcode < 0) return NULL;
if (rcode == 1) {
cf_log_err_cs(cs,
* refer to a server.
*/
if (!server) {
- rcode = cf_item_parse(cs, "virtual_server", PW_TYPE_STRING_PTR,
- &server, NULL);
- if (rcode == 1) { /* compatiblity with 2.0-pre */
- rcode = cf_item_parse(cs, "server", PW_TYPE_STRING_PTR,
- &server, NULL);
- }
+ rcode = cf_item_parse(cs, "virtual_server", FR_ITEM_POINTER(PW_TYPE_STRING, &server), NULL);
if (rcode < 0) return NULL;
}
return this;
}
-#ifdef WITH_PROXY
-static int is_loopback(fr_ipaddr_t const *ipaddr)
-{
- /*
- * We shouldn't proxy on loopback.
- */
- if ((ipaddr->af == AF_INET) &&
- (ipaddr->ipaddr.ip4addr.s_addr == htonl(INADDR_LOOPBACK))) {
- return 1;
- }
-
-#ifdef HAVE_STRUCT_SOCKADDR_IN6
- if ((ipaddr->af == AF_INET6) &&
- (IN6_IS_ADDR_LINKLOCAL(&ipaddr->ipaddr.ip6addr))) {
- return 1;
- }
-#endif
-
- return 0;
-}
-#endif
-
-
#ifdef HAVE_PTHREAD_H
/*
* A child thread which does NOTHING other than read and process
*/
int listen_init(CONF_SECTION *config, rad_listen_t **head,
#ifdef WITH_TLS
- int spawn_flag
+ bool spawn_flag
#else
- UNUSED int spawn_flag
+ UNUSED bool spawn_flag
#endif
- )
+ )
{
- int override = false;
+ bool override = false;
CONF_SECTION *cs = NULL;
rad_listen_t **last;
rad_listen_t *this;
fr_ipaddr_t server_ipaddr;
- int auth_port = 0;
+ uint16_t auth_port = 0;
#ifdef WITH_PROXY
- int defined_proxy = 0;
+ bool defined_proxy = false;
#endif
/*
*
* FIXME: If argv[0] == "vmpsd", then don't listen on auth/acct!
*/
- if (mainconfig.port >= 0) {
- auth_port = mainconfig.port;
+ if (main_config.port > 0) {
+ auth_port = main_config.port;
/*
* -p X but no -i Y on the command-line.
*/
- if ((mainconfig.port > 0) &&
- (mainconfig.myip.af == AF_UNSPEC)) {
+ if (main_config.myip.af == AF_UNSPEC) {
ERROR("The command-line says \"-p %d\", but there is no associated IP address to use",
- mainconfig.port);
+ main_config.port);
return -1;
}
}
* If the IP address was configured on the command-line,
* use that as the "bind_address"
*/
- if (mainconfig.myip.af != AF_UNSPEC) {
+ if (main_config.myip.af != AF_UNSPEC) {
listen_socket_t *sock;
- memcpy(&server_ipaddr, &mainconfig.myip,
+ memcpy(&server_ipaddr, &main_config.myip,
sizeof(server_ipaddr));
override = true;
auth_port = sock->my_port; /* may have been updated in listen_bind */
if (override) {
cs = cf_section_sub_find_name2(config, "server",
- mainconfig.name);
- if (cs) this->server = mainconfig.name;
+ main_config.name);
+ if (cs) this->server = main_config.name;
}
*last = this;
if (override) {
cs = cf_section_sub_find_name2(config, "server",
- mainconfig.name);
- if (cs) this->server = mainconfig.name;
+ main_config.name);
+ if (cs) this->server = main_config.name;
}
*last = this;
* They specified an IP on the command-line, ignore
* all listen sections except the one in '-n'.
*/
- if (mainconfig.myip.af != AF_UNSPEC) {
+ if (main_config.myip.af != AF_UNSPEC) {
CONF_SECTION *subcs;
char const *name2 = cf_section_name2(cs);
cs = cf_section_sub_find_name2(config, "server",
- mainconfig.name);
+ main_config.name);
if (!cs) goto add_sockets;
/*
* proxying is pointless.
*/
if (!*head) {
- ERROR("The server is not configured to listen on any ports. Cannot start.");
+ ERROR("The server is not configured to listen on any ports. Cannot start");
return -1;
}
for (this = *head; this != NULL; this = this->next) {
#ifdef WITH_PROXY
if (this->type == RAD_LISTEN_PROXY) {
- defined_proxy = 1;
+ defined_proxy = true;
}
#endif
#ifdef WITH_TLS
if (!check_config && !spawn_flag && this->tls) {
- cf_log_err_cs(this->cs, "Threading must be enabled for TLS sockets to function properly.");
- cf_log_err_cs(this->cs, "You probably need to do 'radiusd -fxx -l stdout' for debugging");
+ cf_log_err_cs(this->cs, "Threading must be enabled for TLS sockets to function properly");
+ cf_log_err_cs(this->cs, "You probably need to do '%s -fxx -l stdout' for debugging",
+ progname);
return -1;
}
#endif
}
if (this->workers) {
-#ifndef HAVE_PTHREAD_H
- WARN("Setting 'workers' requires 'synchronous'. Disabling 'workers'");
- this->workers = 0;
-#else
- int i, rcode;
+#ifdef HAVE_PTHREAD_H
+ int rcode;
+ uint32_t i;
char buffer[256];
this->print(this, buffer, sizeof(buffer));
rcode = pthread_create(&id, 0, recv_thread, this);
if (rcode != 0) {
ERROR("Thread create failed: %s",
- strerror(rcode));
+ fr_syserror(rcode));
fr_exit(1);
}
DEBUG("Thread %d for %s\n", i, buffer);
}
+#else
+ WARN("Setting 'workers' requires 'synchronous'. Disabling 'workers'");
+ this->workers = 0;
#endif
+
} else {
- event_new_fd(this);
+ radius_update_listener(this);
}
}
* Otherwise, don't do anything.
*/
#ifdef WITH_PROXY
- if ((mainconfig.proxy_requests == true) &&
+ if ((main_config.proxy_requests == true) &&
!check_config &&
(*head != NULL) && !defined_proxy) {
- listen_socket_t *sock = NULL;
- int port = 0;
- home_server home;
+ uint16_t port = 0;
+ home_server_t home;
memset(&home, 0, sizeof(home));
*/
home.proto = IPPROTO_UDP;
home.src_ipaddr = server_ipaddr;
-
- /*
- * Find the first authentication port,
- * and use it
- */
- for (this = *head; this != NULL; this = this->next) {
- switch (this->type) {
- case RAD_LISTEN_AUTH:
- sock = this->data;
-
- if (is_loopback(&sock->my_ipaddr)) continue;
-
- if (home.src_ipaddr.af == AF_UNSPEC) {
- home.src_ipaddr = sock->my_ipaddr;
- }
- port = sock->my_port + 2;
- break;
-#ifdef WITH_ACCT
- case RAD_LISTEN_ACCT:
- sock = this->data;
-
- if (is_loopback(&sock->my_ipaddr)) continue;
-
- if (home.src_ipaddr.af == AF_UNSPEC) {
- home.src_ipaddr = sock->my_ipaddr;
- }
- port = sock->my_port + 1;
- break;
-#endif
- default:
- break;
- }
- }
+ port = 0;
/*
* Address is still unspecified, use IPv4.
return -1;
}
- if (!event_new_fd(this)) {
- listen_free(&this);
- listen_free(head);
- return -1;
- }
+ radius_update_listener(this);
}
#endif
}
#ifdef WITH_STATS
-RADCLIENT_LIST *listener_find_client_list(fr_ipaddr_t const *ipaddr,
- int port)
+RADCLIENT_LIST *listener_find_client_list(fr_ipaddr_t const *ipaddr, uint16_t port)
{
rad_listen_t *this;
- for (this = mainconfig.listen; this != NULL; this = this->next) {
+ for (this = main_config.listen; this != NULL; this = this->next) {
listen_socket_t *sock;
if ((this->type != RAD_LISTEN_AUTH)
}
#endif
-rad_listen_t *listener_find_byipaddr(fr_ipaddr_t const *ipaddr, int port, int proto)
+rad_listen_t *listener_find_byipaddr(fr_ipaddr_t const *ipaddr, uint16_t port, int proto)
{
rad_listen_t *this;
- for (this = mainconfig.listen; this != NULL; this = this->next) {
+ for (this = main_config.listen; this != NULL; this = this->next) {
listen_socket_t *sock;
sock = this->data;
/*
* Failed to find a specific one. Find INADDR_ANY
*/
- for (this = mainconfig.listen; this != NULL; this = this->next) {
+ for (this = main_config.listen; this != NULL; this = this->next) {
listen_socket_t *sock;
sock = this->data;
RCSID("$Id$")
#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
+# include <sys/stat.h>
#endif
#ifdef HAVE_SYSLOG_H
-# include <syslog.h>
+# include <syslog.h>
#endif
+#include <sys/file.h>
+
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
+
+bool rate_limit = true;
+
/*
* Logging facility names
*/
{ ": Error: ", L_ERR },
{ ": WARNING: ", L_DBG_WARN },
{ ": ERROR: ", L_DBG_ERR },
- { ": WARNING: ", L_DBG_WARN2 },
- { ": ERROR: ", L_DBG_ERR2 },
+ { ": WARNING: ", L_DBG_WARN_REQ },
+ { ": ERROR: ", L_DBG_ERR_REQ },
{ NULL, 0 }
};
{ VTC_BOLD VTC_YELLOW, L_WARN },
{ VTC_BOLD VTC_RED, L_DBG_ERR },
{ VTC_BOLD VTC_YELLOW, L_DBG_WARN },
- { VTC_BOLD VTC_RED, L_DBG_ERR2 },
- { VTC_BOLD VTC_YELLOW, L_DBG_WARN2 },
+ { VTC_BOLD VTC_RED, L_DBG_ERR_REQ },
+ { VTC_BOLD VTC_YELLOW, L_DBG_WARN_REQ },
{ NULL, 0 }
};
bool log_dates_utc = false;
-
fr_log_t default_log = {
.colourise = true,
.fd = STDOUT_FILENO,
- .dest = L_DST_STDOUT,
+ .dst = L_DST_STDOUT,
.file = NULL,
.debug_file = NULL,
};
+static int stderr_fd = -1; //!< The original unmolested stderr file descriptor
+static int stdout_fd = -1; //!< The original unmolested stdout file descriptor
+
+static char const spaces[] = " ";
+
+/** On fault, reset STDOUT and STDERR to something useful.
+ *
+ * @return 0
+ */
+static int _restore_std(UNUSED int sig)
+{
+ if ((stderr_fd > 0) && (stdout_fd > 0)) {
+ dup2(stderr_fd, STDOUT_FILENO);
+ dup2(stdout_fd, STDERR_FILENO);
+ return 0;
+ }
+
+ if (default_log.fd > 0) {
+ dup2(default_log.fd, STDOUT_FILENO);
+ dup2(default_log.fd, STDERR_FILENO);
+ return 0;
+ }
+
+ return 0;
+}
+
+/** Pass debug logging through to vradlog
+ *
+ */
+static void CC_HINT(format (printf, 1, 2)) _radlog_info(char const *msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg);
+ vradlog(L_INFO, msg, ap);
+ va_end(ap);
+}
+
+/** Initialise file descriptors based on logging destination
+ *
+ * @param log Logger to manipulate.
+ * @param daemonize Whether the server is starting as a daemon.
+ * @return 0 on success -1 on failure.
+ */
+int radlog_init(fr_log_t *log, bool daemonize)
+{
+ int devnull;
+
+ rate_limit = daemonize;
+
+ /*
+ * If we're running in foreground mode, save STDIN /
+ * STDERR as higher FDs, which won't get used by anyone
+ * else. When we fork/exec a program, it's STD FDs will
+ * get set to pipes. We later set STDOUT / STDERR to
+ * /dev/null, so that any library trying to write to them
+ * doesn't screw anything up.
+ *
+ * Then, when something goes wrong, restore them so that
+ * any debugger called from the panic action has access
+ * to STDOUT / STDERR.
+ */
+ if (!daemonize) {
+ fr_fault_set_cb(_restore_std);
+
+ stdout_fd = dup(STDOUT_FILENO);
+ stderr_fd = dup(STDERR_FILENO);
+ }
+
+ devnull = open("/dev/null", O_RDWR);
+ if (devnull < 0) {
+ fr_strerror_printf("Error opening /dev/null: %s", fr_syserror(errno));
+ return -1;
+ }
+
+ /*
+ * STDOUT & STDERR go to /dev/null, unless we have "-x",
+ * then STDOUT & STDERR go to the "-l log" destination.
+ *
+ * The complexity here is because "-l log" can go to
+ * STDOUT or STDERR, too.
+ */
+ if (log->dst == L_DST_STDOUT) {
+ setlinebuf(stdout);
+ log->fd = STDOUT_FILENO;
+
+ /*
+ * If we're debugging, allow STDERR to go to
+ * STDOUT too, for executed programs,
+ */
+ if (debug_flag) {
+ dup2(STDOUT_FILENO, STDERR_FILENO);
+ } else {
+ dup2(devnull, STDERR_FILENO);
+ }
+
+ } else if (log->dst == L_DST_STDERR) {
+ setlinebuf(stderr);
+ log->fd = STDERR_FILENO;
+
+ /*
+ * If we're debugging, allow STDOUT to go to
+ * STDERR too, for executed programs,
+ */
+ if (debug_flag) {
+ dup2(STDERR_FILENO, STDOUT_FILENO);
+ } else {
+ dup2(devnull, STDOUT_FILENO);
+ }
+
+ } else if (log->dst == L_DST_SYSLOG) {
+ /*
+ * Discard STDOUT and STDERR no matter what the
+ * status of debugging. Syslog isn't a file
+ * descriptor, so we can't use it.
+ */
+ dup2(devnull, STDOUT_FILENO);
+ dup2(devnull, STDERR_FILENO);
+
+ } else if (debug_flag) {
+ /*
+ * If we're debugging, allow STDOUT and STDERR to
+ * go to the log file.
+ */
+ dup2(log->fd, STDOUT_FILENO);
+ dup2(log->fd, STDERR_FILENO);
+
+ } else {
+ /*
+ * Not debugging, and the log isn't STDOUT or
+ * STDERR. Ensure that we move both of them to
+ * /dev/null, so that the calling terminal can
+ * exit, and the output from executed programs
+ * doesn't pollute STDOUT / STDERR.
+ */
+ dup2(devnull, STDOUT_FILENO);
+ dup2(devnull, STDERR_FILENO);
+ }
+
+ close(devnull);
+
+ /*
+ * This handles setting up all the talloc logging
+ * and callbacks too.
+ */
+ fr_fault_set_log_fn(_radlog_info);
+ fr_fault_set_log_fd(log->fd);
+
+ return 0;
+}
+
/*
* Log the message to the logfile. Include the severity and
* a time stamp.
*/
-DIAG_OFF(format-nonliteral)
int vradlog(log_type_t type, char const *fmt, va_list ap)
{
unsigned char *p;
- char buffer[8192];
+ char buffer[10240]; /* The largest config item size, then extra for prefixes and suffixes */
char *unsan;
size_t len;
int colourise = default_log.colourise;
* If we don't want any messages, then
* throw them away.
*/
- if (default_log.dest == L_DST_NULL) {
+ if (default_log.dst == L_DST_NULL) {
return 0;
}
len = 0;
if (colourise) {
- len += strlcpy(buffer + len, fr_int2str(colours, type, ""),
- sizeof(buffer) - len) ;
- if (len == 0) colourise = false;
+ len += strlcpy(buffer + len, fr_int2str(colours, type, ""), sizeof(buffer) - len) ;
+ if (len == 0) {
+ colourise = false;
+ }
}
/*
/*
* Don't print timestamps to syslog, it does that for us.
- * Don't print timestamps for low levels of debugging.
+ * Don't print timestamps and error types for low levels
+ * of debugging.
*
* Print timestamps for non-debugging, and for high levels
* of debugging.
*/
- if ((default_log.dest != L_DST_SYSLOG) &&
- (debug_flag != 1) && (debug_flag != 2)) {
- time_t timeval;
-
- timeval = time(NULL);
- CTIME_R(&timeval, buffer + len, sizeof(buffer) - len - 1);
-
- len = strlen(buffer);
-
- len += strlcpy(buffer + len,
- fr_int2str(levels, type, ": "),
- sizeof(buffer) - len);
- }
-
- switch (type) {
- case L_DBG_WARN:
- len += strlcpy(buffer + len, "WARNING: ", sizeof(buffer) - len);
- break;
+ if (default_log.dst != L_DST_SYSLOG) {
+ if ((debug_flag != 1) && (debug_flag != 2)) {
+ time_t timeval;
- case L_DBG_ERR:
- len += strlcpy(buffer + len, "ERROR: ", sizeof(buffer) - len);
- break;
+ timeval = time(NULL);
+ CTIME_R(&timeval, buffer + len, sizeof(buffer) - len - 1);
- default:
- break;
+ len = strlen(buffer);
+ len += strlcpy(buffer + len, fr_int2str(levels, type, ": "), sizeof(buffer) - len);
+ } else goto add_prefix;
+ } else {
+ add_prefix:
+ if (len < sizeof(buffer)) switch (type) {
+ case L_DBG_WARN:
+ len += strlcpy(buffer + len, "WARNING: ", sizeof(buffer) - len);
+ break;
+
+ case L_DBG_ERR:
+ len += strlcpy(buffer + len, "ERROR: ", sizeof(buffer) - len);
+ break;
+
+ default:
+ break;
+ }
}
if (len < sizeof(buffer)) {
}
/*
- * Filter out characters not in Latin-1.
+ * Filter out control chars and non UTF8 chars
*/
for (p = (unsigned char *)unsan; *p != '\0'; p++) {
- if (*p == '\r' || *p == '\n')
+ int clen;
+
+ switch (*p) {
+ case '\r':
+ case '\n':
*p = ' ';
- else if (*p == '\t') continue;
- else if (*p < 32 || (*p >= 128 && *p <= 160))
- *p = '?';
+ break;
+
+ case '\t':
+ continue;
+
+ default:
+ clen = fr_utf8_char(p);
+ if (!clen) {
+ *p = '?';
+ continue;
+ }
+ p += (clen - 1);
+ break;
+ }
}
if (colourise && (len < sizeof(buffer))) {
buffer[sizeof(buffer) - 1] = '\0';
}
- switch (default_log.dest) {
+ switch (default_log.dst) {
#ifdef HAVE_SYSLOG_H
case L_DST_SYSLOG:
switch(type) {
- case L_DBG:
- case L_WARN:
- case L_DBG_WARN:
- case L_DBG_WARN2:
- case L_DBG_ERR:
- case L_DBG_ERR2:
- type = LOG_DEBUG;
- break;
- case L_AUTH:
- case L_PROXY:
- case L_ACCT:
- type = LOG_NOTICE;
- break;
- case L_INFO:
- type = LOG_INFO;
- break;
- case L_ERR:
- type = LOG_ERR;
- break;
+ case L_DBG:
+ case L_WARN:
+ case L_DBG_WARN:
+ case L_DBG_ERR:
+ case L_DBG_ERR_REQ:
+ case L_DBG_WARN_REQ:
+ type = LOG_DEBUG;
+ break;
+ case L_AUTH:
+ case L_PROXY:
+ case L_ACCT:
+ type = LOG_NOTICE;
+ break;
+ case L_INFO:
+ type = LOG_INFO;
+ break;
+ case L_ERR:
+ type = LOG_ERR;
+ break;
}
syslog(type, "%s", buffer);
break;
return 0;
}
-DIAG_ON(format-nonliteral)
int radlog(log_type_t type, char const *msg, ...)
{
{
vp_cursor_t cursor;
char tmpPair[70];
- for (vp = paircursor(&cursor, &vp);
+ for (vp = fr_cursor_init(&cursor, &vp);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
vp_prints(tmpPair, sizeof(tmpPair), vp);
DEBUG2(" %s", tmpPair);
}
}
+inline bool debug_enabled(log_type_t type, log_debug_t lvl)
+{
+ if ((type & L_DBG) && (debug_flag != 0) && (lvl > debug_flag)) return true;
+
+ return false;
+}
+
+inline bool rate_limit_enabled(void)
+{
+ if (rate_limit || (debug_flag < 1)) return true;
+
+ return false;
+}
+
inline bool radlog_debug_enabled(log_type_t type, log_debug_t lvl, REQUEST *request)
{
/*
* then don't log the message.
*/
if ((type & L_DBG) &&
- ((request && request->radlog && (lvl > request->options)) ||
+ ((request && request->log.func && (lvl > request->log.lvl)) ||
((debug_flag != 0) && (lvl > debug_flag)))) {
- return false;
+ return false;
}
return true;
}
-void radlog_request(log_type_t type, log_debug_t lvl, REQUEST *request, char const *msg, ...)
+void vradlog_request(log_type_t type, log_debug_t lvl, REQUEST *request, char const *msg, va_list ap)
{
size_t len = 0;
char const *filename = default_log.file;
FILE *fp = NULL;
- va_list ap;
- char buffer[8192];
+ char buffer[10240]; /* The largest config item size, then extra for prefixes and suffixes */
char *p;
char const *extra = "";
+ va_list aq;
- va_start(ap, msg);
+ rad_assert(request);
/*
* Debug messages get treated specially.
if ((type & L_DBG) != 0) {
if (!radlog_debug_enabled(type, lvl, request)) {
- va_end(ap);
return;
}
}
if (request && filename) {
- radlog_func_t rl = request->radlog;
+ radlog_func_t rl = request->log.func;
- request->radlog = NULL;
+ request->log.func = NULL;
/*
* This is SLOW! Doing it for every log message
/* FIXME: escape chars! */
if (radius_xlat(buffer, sizeof(buffer), request, filename, NULL, NULL) < 0) {
- va_end(ap);
return;
}
- request->radlog = rl;
+ request->log.func = rl;
p = strrchr(buffer, FR_DIR_SEP);
if (p) {
*p = '\0';
if (rad_mkdir(buffer, S_IRWXU) < 0) {
- ERROR("Failed creating %s: %s", buffer, strerror(errno));
- va_end(ap);
+ ERROR("Failed creating %s: %s", buffer, fr_syserror(errno));
return;
}
*p = FR_DIR_SEP;
{
CTIME_R(&timeval, buffer, sizeof(buffer) - 1);
}
+
len = strlen(buffer);
p = strrchr(buffer, '\n');
if (p) {
p[1] = '\0';
}
- len += strlcpy(buffer + len,
- fr_int2str(levels, type, ": "),
- sizeof(buffer) - len);
-
+ len += strlcpy(buffer + len, fr_int2str(levels, type, ": "), sizeof(buffer) - len);
if (len >= sizeof(buffer)) goto finish;
}
if (request && request->module[0]) {
- len = snprintf(buffer + len, sizeof(buffer) - len, "%s : ",
- request->module);
-
+ len = snprintf(buffer + len, sizeof(buffer) - len, "%s : ", request->module);
if (len >= sizeof(buffer)) goto finish;
}
- vsnprintf(buffer + len, sizeof(buffer) - len, msg, ap);
+ /*
+ * If we don't copy the original ap we get a segfault from vasprintf. This is apparently
+ * due to ap sometimes being implemented with a stack offset which is invalidated if
+ * ap is passed into another function. See here:
+ * http://julipedia.meroh.net/2011/09/using-vacopy-to-safely-pass-ap.html
+ *
+ * I don't buy that explanation, but doing a va_copy here does prevent SEGVs seen when
+ * running unit tests which generate errors under CI.
+ */
+ va_copy(aq, ap);
+ vsnprintf(buffer + len, sizeof(buffer) - len, msg, aq);
+ va_end(aq);
finish:
switch (type) {
case L_DBG_WARN:
extra = "WARNING: ";
- type = L_DBG_WARN2;
+ type = L_DBG_WARN_REQ;
break;
case L_DBG_ERR:
extra = "ERROR: ";
- type = L_DBG_ERR2;
+ type = L_DBG_ERR_REQ;
break;
default:
break;
}
if (!fp) {
+
+ if (debug_flag > 2) extra = "";
+
if (request) {
- radlog(type, "(%u) %s%s", request->number, extra, buffer);
+ uint8_t indent;
+
+ indent = request->log.indent > sizeof(spaces) ?
+ sizeof(spaces) :
+ request->log.indent;
+ radlog(type, "(%u) %.*s%s%s", request->number, indent, spaces, extra, buffer);
} else {
radlog(type, "%s%s", extra, buffer);
}
} else {
- if (request) fprintf(fp, "(%u) ", request->number);
+ if (request) {
+ fprintf(fp, "(%u) %s", request->number, extra);
+ }
fputs(buffer, fp);
fputc('\n', fp);
fclose(fp);
}
+}
+
+/** Martial variadic log arguments into a va_list and pass to normal logging functions
+ *
+ * @see radlog_request_error for more details.
+ *
+ * @param type the log category.
+ * @param lvl of debugging this message should be displayed at.
+ * @param request The current request.
+ * @param msg format string.
+ */
+void radlog_request(log_type_t type, log_debug_t lvl, REQUEST *request, char const *msg, ...)
+{
+ va_list ap;
+ rad_assert(request);
+
+ if (request->log.func == NULL) return;
+
+ va_start(ap, msg);
+ request->log.func(type, lvl, request, msg, ap);
va_end(ap);
}
-void log_talloc(char const *msg)
+/** Martial variadic log arguments into a va_list and pass to error logging functions
+ *
+ * This could all be done in a macro, but it turns out some implementations of the
+ * variadic macros do not work at all well if the va_list being written to is further
+ * up the stack (which is required as you still need a function to convert the elipses
+ * into a va_list).
+ *
+ * So, we use this small wrapper function instead, which will hopefully guarantee
+ * consistent behaviour.
+ *
+ * @param type the log category.
+ * @param lvl of debugging this message should be displayed at.
+ * @param request The current request.
+ * @param msg format string.
+ */
+void radlog_request_error(log_type_t type, log_debug_t lvl, REQUEST *request, char const *msg, ...)
{
- INFO("%s", msg);
+ va_list ap;
+
+ rad_assert(request);
+
+ va_start(ap, msg);
+ if (request->log.func) {
+ request->log.func(type, lvl, request, msg, ap);
+ }
+ vmodule_failure_msg(request, msg, ap);
+ va_end(ap);
}
-void log_talloc_report(TALLOC_CTX *ctx)
+/** Parse error, write out string we were parsing, and a message indicating the error
+ *
+ * @param type the log category.
+ * @param lvl of debugging this message should be displayed at.
+ * @param request The current request.
+ * @param fmt string we were parsing.
+ * @param idx The position of the marker relative to the string.
+ * @param error What the parse error was.
+ */
+void radlog_request_marker(log_type_t type, log_debug_t lvl, REQUEST *request,
+ char const *fmt, size_t idx, char const *error)
{
- FILE *fd;
- char const *null_ctx = NULL;
- int i = 0;
+ char const *prefix = "";
+ uint8_t indent;
+
+ rad_assert(request);
+
+ if (idx >= sizeof(spaces)) {
+ size_t offset = (idx - (sizeof(spaces) - 1)) + (sizeof(spaces) * 0.75);
+ idx -= offset;
+ fmt += offset;
- if (ctx) {
- null_ctx = talloc_get_name(NULL);
+ prefix = "... ";
}
- fd = fdopen(default_log.fd, "w");
- if (!fd) {
- ERROR("Couldn't write memory report, fdopen failed: %s", strerror(errno));
+ /*
+ * Don't want format markers being indented
+ */
+ indent = request->log.indent;
+ request->log.indent = 0;
+
+ radlog_request(type, lvl, request, "%s%s", prefix, fmt);
+ radlog_request(type, lvl, request, "%s%.*s^ %s", prefix, (int) idx, spaces, error);
+
+ request->log.indent = indent;
+}
+
+typedef struct fr_logfile_entry_t {
+ int fd;
+ int dup;
+ uint32_t hash;
+ time_t last_used;
+ char *filename;
+} fr_logfile_entry_t;
+
+
+struct fr_logfile_t {
+ uint32_t max_entries;
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_t mutex;
+#endif
+ fr_logfile_entry_t *entries;
+};
+
- return;
+#ifdef HAVE_PTHREAD_H
+#define PTHREAD_MUTEX_LOCK pthread_mutex_lock
+#define PTHREAD_MUTEX_UNLOCK pthread_mutex_unlock
+
+#else
+/*
+ * This is easier than ifdef's throughout the code.
+ */
+#define PTHREAD_MUTEX_LOCK(_x)
+#define PTHREAD_MUTEX_UNLOCK(_x)
+#endif
+
+static int _logfile_free(fr_logfile_t *lf)
+{
+ uint32_t i;
+
+ PTHREAD_MUTEX_LOCK(&lf->mutex);
+
+ for (i = 0; i < lf->max_entries; i++) {
+ if (!lf->entries[i].filename) continue;
+
+ close(lf->entries[i].fd);
}
- if (!ctx) {
- talloc_report_full(NULL, fd);
- } else {
- do {
- INFO("Context level %i", i++);
+ PTHREAD_MUTEX_UNLOCK(&lf->mutex);
+
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_destroy(&lf->mutex);
+#endif
+
+ return 0;
+}
+
- talloc_report_full(ctx, fd);
- } while ((ctx = talloc_parent(ctx)) && (talloc_get_name(ctx) != null_ctx)); /* Stop before we hit NULL ctx */
+/** Initialize a way for multiple threads to log to one or more files.
+ *
+ * @param ctx The talloc context
+ * @return the new context, or NULL on error.
+ */
+fr_logfile_t *fr_logfile_init(TALLOC_CTX *ctx)
+{
+ fr_logfile_t *lf;
+
+ lf = talloc_zero(ctx, fr_logfile_t);
+ if (!lf) return NULL;
+
+ lf->entries = talloc_zero_array(lf, fr_logfile_entry_t, 64);
+ if (!lf->entries) {
+ talloc_free(lf);
+ return NULL;
}
- fclose(fd);
+#ifdef HAVE_PTHREAD_H
+ if (pthread_mutex_init(&lf->mutex, NULL) != 0) {
+ talloc_free(lf);
+ return NULL;
+ }
+#endif
+
+ lf->max_entries = 64;
+
+ talloc_set_destructor(lf, _logfile_free);
+
+ return lf;
}
+
+/** Open a new log file, or maybe an existing one.
+ *
+ * When multithreaded, the FD is locked via a mutex. This way we're
+ * sure that no other thread is writing to the file.
+ *
+ * @param lf The logfile context returned from fr_logfile_init().
+ * @param filename the file to open.
+ * @param permissions to use.
+ * @return an FD used to write to the file, or -1 on error.
+ */
+int fr_logfile_open(fr_logfile_t *lf, char const *filename, mode_t permissions)
+{
+ uint32_t i;
+ uint32_t hash;
+ time_t now = time(NULL);
+ struct stat st;
+
+ if (!lf || !filename) return -1;
+
+ hash = fr_hash_string(filename);
+
+ PTHREAD_MUTEX_LOCK(&lf->mutex);
+
+ /*
+ * Clean up old entries.
+ */
+ for (i = 0; i < lf->max_entries; i++) {
+ if (!lf->entries[i].filename) continue;
+
+ /*
+ * FIXME: make this configurable?
+ */
+ if ((lf->entries[i].last_used + 30) < now) {
+ /*
+ * This will block forever if a thread is
+ * doing something stupid.
+ */
+ TALLOC_FREE(lf->entries[i].filename);
+ close(lf->entries[i].fd);
+ }
+ }
+
+ /*
+ * Find the matching entry.
+ */
+ for (i = 0; i < lf->max_entries; i++) {
+ if (!lf->entries[i].filename) continue;
+
+ if (lf->entries[i].hash == hash) {
+ /*
+ * Same hash but different filename. Give up.
+ */
+ if (strcmp(lf->entries[i].filename, filename) != 0) {
+ PTHREAD_MUTEX_UNLOCK(&lf->mutex);
+ return -1;
+ }
+ /*
+ * Someone else failed to create the entry.
+ */
+ if (!lf->entries[i].filename) {
+ PTHREAD_MUTEX_UNLOCK(&lf->mutex);
+ return -1;
+ }
+ goto do_return;
+ }
+ }
+
+ /*
+ * Find an unused entry
+ */
+ for (i = 0; i < lf->max_entries; i++) {
+ if (!lf->entries[i].filename) break;
+ }
+
+ if (i >= lf->max_entries) {
+ fr_strerror_printf("Too many different filenames");
+ PTHREAD_MUTEX_UNLOCK(&(lf->mutex));
+ return -1;
+ }
+
+ /*
+ * Create a new entry.
+ */
+
+ lf->entries[i].hash = hash;
+ lf->entries[i].filename = talloc_strdup(lf->entries, filename);
+ lf->entries[i].fd = -1;
+
+ lf->entries[i].fd = open(filename, O_WRONLY | O_APPEND | O_CREAT, permissions);
+ if (lf->entries[i].fd < 0) {
+ mode_t dirperm;
+ char *p, *dir;
+
+ /*
+ * Maybe the directory doesn't exist. Try to
+ * create it.
+ */
+ dir = talloc_strdup(lf, filename);
+ if (!dir) goto error;
+ p = strrchr(dir, FR_DIR_SEP);
+ if (!p) {
+ fr_strerror_printf("No '/' in '%s'", filename);
+ goto error;
+ }
+ *p = '\0';
+
+ /*
+ * Ensure that the 'x' bit is set, so that we can
+ * read the directory.
+ */
+ dirperm = permissions;
+ if ((dirperm & 0600) != 0) dirperm |= 0100;
+ if ((dirperm & 0060) != 0) dirperm |= 0010;
+ if ((dirperm & 0006) != 0) dirperm |= 0001;
+
+ if (rad_mkdir(dir, dirperm) < 0) {
+ fr_strerror_printf("Failed to create directory %s: %s",
+ dir, strerror(errno));
+ talloc_free(dir);
+ goto error;
+ }
+ talloc_free(dir);
+
+ lf->entries[i].fd = open(filename, O_WRONLY | O_CREAT, permissions);
+ if (lf->entries[i].fd < 0) {
+ fr_strerror_printf("Failed to open file %s: %s",
+ filename, strerror(errno));
+ goto error;
+ } /* else fall through to creating the rest of the entry */
+ } /* else the file was already opened */
+
+do_return:
+ /*
+ * Lock from the start of the file.
+ */
+ if (lseek(lf->entries[i].fd, 0, SEEK_SET) < 0) {
+ fr_strerror_printf("Failed to seek in file %s: %s",
+ filename, strerror(errno));
+
+ error:
+ lf->entries[i].hash = 0;
+ TALLOC_FREE(lf->entries[i].filename);
+ close(lf->entries[i].fd);
+ lf->entries[i].fd = -1;
+
+ PTHREAD_MUTEX_UNLOCK(&(lf->mutex));
+ return -1;
+ }
+
+ if (rad_lockfd(lf->entries[i].fd, 0) < 0) {
+ fr_strerror_printf("Failed to lock file %s: %s",
+ filename, strerror(errno));
+ goto error;
+ }
+
+ /*
+ * Maybe someone deleted the file while we were waiting
+ * for the lock. If so, re-open it.
+ */
+ if (fstat(lf->entries[i].fd, &st) < 0) {
+ fr_strerror_printf("Failed to stat file %s: %s",
+ filename, strerror(errno));
+ goto error;
+ }
+
+ if (st.st_nlink == 0) {
+ close(lf->entries[i].fd);
+ lf->entries[i].fd = open(filename, O_WRONLY | O_CREAT, permissions);
+ if (lf->entries[i].fd < 0) {
+ fr_strerror_printf("Failed to open file %s: %s",
+ filename, strerror(errno));
+ goto error;
+ }
+ }
+
+ /*
+ * Seek to the end of the file before returning the FD to
+ * the caller.
+ */
+ lseek(lf->entries[i].fd, 0, SEEK_END);
+
+ /*
+ * Return holding the mutex for the entry.
+ */
+ lf->entries[i].last_used = now;
+ lf->entries[i].dup = dup(lf->entries[i].fd);
+ if (lf->entries[i].dup < 0) {
+ fr_strerror_printf("Failed calling dup(): %s",
+ strerror(errno));
+ goto error;
+ }
+
+ return lf->entries[i].dup;
+}
+
+/** Close the log file. Really just return it to the pool.
+ *
+ * When multithreaded, the FD is locked via a mutex. This way we're
+ * sure that no other thread is writing to the file. This function
+ * will unlock the mutex, so that other threads can write to the file.
+ *
+ * @param lf The logfile context returned from fr_logfile_init()
+ * @param fd the FD to close (i.e. return to the pool)
+ * @return 0 on success, or -1 on error
+ */
+int fr_logfile_close(fr_logfile_t *lf, int fd)
+{
+ uint32_t i;
+
+ for (i = 0; i < lf->max_entries; i++) {
+ if (!lf->entries[i].filename) continue;
+
+ /*
+ * Unlock the bytes that we had previously locked.
+ */
+ if (lf->entries[i].dup == fd) {
+ (void) rad_unlockfd(lf->entries[i].dup, 0);
+ close(lf->entries[i].dup); /* releases the fcntl lock */
+ lf->entries[i].dup = -1;
+
+ PTHREAD_MUTEX_UNLOCK(&(lf->mutex));
+ return 0;
+ }
+ }
+
+ PTHREAD_MUTEX_UNLOCK(&(lf->mutex));
+
+ fr_strerror_printf("Attempt to unlock file which does not exist");
+ return -1;
+}
+
+int fr_logfile_unlock(fr_logfile_t *lf, int fd)
+{
+ uint32_t i;
+
+ for (i = 0; i < lf->max_entries; i++) {
+ if (!lf->entries[i].filename) continue;
+
+ if (lf->entries[i].dup == fd) {
+ lf->entries[i].dup = -1;
+ PTHREAD_MUTEX_UNLOCK(&(lf->mutex));
+ return 0;
+ }
+ }
+
+ PTHREAD_MUTEX_UNLOCK(&(lf->mutex));
+
+ fr_strerror_printf("Attempt to unlock file which does not exist");
+ return -1;
+}
#include <sys/stat.h>
-#ifdef HAVE_SYS_RESOURCE_H
-#include <sys/resource.h>
-#endif
-
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
#include <grp.h>
#endif
-#ifdef HAVE_SYS_PRCTL_H
-#include <sys/prctl.h>
-#endif
-
#ifdef HAVE_SYSLOG_H
# include <syslog.h>
#endif
#include <fcntl.h>
#endif
-struct main_config_t mainconfig;
+struct main_config_t main_config;
char *debug_condition = NULL;
-extern int log_dates_utc;
+extern bool log_dates_utc;
typedef struct cached_config_t {
struct cached_config_t *next;
*/
static char const *localstatedir = NULL;
static char const *prefix = NULL;
-static char my_name;
+static char const *my_name = NULL;
static char const *sbindir = NULL;
static char const *run_dir = NULL;
-static char *syslog_facility = NULL;
+static char const *syslog_facility = NULL;
static bool do_colourise = false;
+static char const *radius_dir = NULL; //!< Path to raddb directory
+
/*
* Security configuration for the server.
*/
static const CONF_PARSER security_config[] = {
- { "max_attributes", PW_TYPE_INTEGER, 0, &fr_max_attributes, STRINGIFY(0) },
- { "reject_delay", PW_TYPE_INTEGER, 0, &mainconfig.reject_delay, STRINGIFY(0) },
- { "status_server", PW_TYPE_BOOLEAN, 0, &mainconfig.status_server, "no"},
+ { "max_attributes", FR_CONF_POINTER(PW_TYPE_INTEGER, &fr_max_attributes), STRINGIFY(0) },
+ { "reject_delay", FR_CONF_POINTER(PW_TYPE_INTEGER, &main_config.reject_delay), STRINGIFY(0) },
+ { "status_server", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.status_server), "no"},
+ { "allow_vulnerable_openssl", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.allow_vulnerable_openssl), "no"},
{ NULL, -1, 0, NULL, NULL }
};
* Logging configuration for the server.
*/
static const CONF_PARSER logdest_config[] = {
- { "destination", PW_TYPE_STRING_PTR, 0, &radlog_dest, "files" },
- { "syslog_facility", PW_TYPE_STRING_PTR, 0, &syslog_facility, STRINGIFY(0) },
+ { "destination", FR_CONF_POINTER(PW_TYPE_STRING, &radlog_dest), "files" },
+ { "syslog_facility", FR_CONF_POINTER(PW_TYPE_STRING, &syslog_facility), STRINGIFY(0) },
- { "file", PW_TYPE_STRING_PTR, 0, &mainconfig.log_file, "${logdir}/radius.log" },
- { "requests", PW_TYPE_STRING_PTR, 0, &default_log.file, NULL },
+ { "file", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.log_file), "${logdir}/radius.log" },
+ { "requests", FR_CONF_POINTER(PW_TYPE_STRING, &default_log.file), NULL },
{ NULL, -1, 0, NULL, NULL }
};
static const CONF_PARSER serverdest_config[] = {
- { "log", PW_TYPE_SUBSECTION, 0, NULL, (void const *) logdest_config },
- { "log_file", PW_TYPE_STRING_PTR, 0, &mainconfig.log_file, NULL },
- { "log_destination", PW_TYPE_STRING_PTR, 0, &radlog_dest, NULL },
- { "use_utc", PW_TYPE_BOOLEAN, 0, &log_dates_utc, NULL },
+ { "log", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) logdest_config },
+ { "log_file", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.log_file), NULL },
+ { "log_destination", FR_CONF_POINTER(PW_TYPE_STRING, &radlog_dest), NULL },
+ { "use_utc", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &log_dates_utc), NULL },
{ NULL, -1, 0, NULL, NULL }
};
static const CONF_PARSER log_config_nodest[] = {
- { "stripped_names", PW_TYPE_BOOLEAN, 0, &log_stripped_names,"no" },
- { "auth", PW_TYPE_BOOLEAN, 0, &mainconfig.log_auth, "no" },
- { "auth_badpass", PW_TYPE_BOOLEAN, 0, &mainconfig.log_auth_badpass, "no" },
- { "auth_goodpass", PW_TYPE_BOOLEAN, 0, &mainconfig.log_auth_goodpass, "no" },
- { "msg_badpass", PW_TYPE_STRING_PTR, 0, &mainconfig.auth_badpass_msg, NULL},
- { "msg_goodpass", PW_TYPE_STRING_PTR, 0, &mainconfig.auth_goodpass_msg, NULL},
- { "colourise", PW_TYPE_BOOLEAN, 0, &do_colourise, NULL },
- { "use_utc", PW_TYPE_BOOLEAN, 0, &log_dates_utc, NULL },
+ { "stripped_names", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &log_stripped_names),"no" },
+ { "auth", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.log_auth), "no" },
+ { "auth_badpass", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.log_auth_badpass), "no" },
+ { "auth_goodpass", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.log_auth_goodpass), "no" },
+ { "msg_badpass", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.auth_badpass_msg), NULL},
+ { "msg_goodpass", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.auth_goodpass_msg), NULL},
+ { "colourise",FR_CONF_POINTER(PW_TYPE_BOOLEAN, &do_colourise), NULL },
+ { "use_utc", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &log_dates_utc), NULL },
+ { "msg_denied", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.denied_msg),
+ "You are already logged in - access denied" },
{ NULL, -1, 0, NULL, NULL }
};
* hard-coded defines for the locations of the various
* files.
*/
- { "name", PW_TYPE_STRING_PTR, 0, &my_name, "radiusd"},
- { "prefix", PW_TYPE_STRING_PTR, 0, &prefix, "/usr/local"},
- { "localstatedir", PW_TYPE_STRING_PTR, 0, &localstatedir, "${prefix}/var"},
- { "sbindir", PW_TYPE_STRING_PTR, 0, &sbindir, "${prefix}/sbin"},
- { "logdir", PW_TYPE_STRING_PTR, 0, &radlog_dir, "${localstatedir}/log"},
- { "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" },
- { "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) },
- { "max_requests", PW_TYPE_INTEGER, 0, &mainconfig.max_requests, STRINGIFY(MAX_REQUESTS) },
-#ifdef DELETE_BLOCKED_REQUESTS
- { "delete_blocked_requests", PW_TYPE_INTEGER, 0, &mainconfig.kill_unresponsive_children, STRINGIFY(false) },
-#endif
- { "pidfile", PW_TYPE_STRING_PTR, 0, &mainconfig.pid_file, "${run_dir}/radiusd.pid"},
- { "checkrad", PW_TYPE_STRING_PTR, 0, &mainconfig.checkrad, "${sbindir}/checkrad" },
-
- { "debug_level", PW_TYPE_INTEGER, 0, &mainconfig.debug_level, "0"},
+ { "name", FR_CONF_POINTER(PW_TYPE_STRING, &my_name), "radiusd"},
+ { "prefix", FR_CONF_POINTER(PW_TYPE_STRING, &prefix), "/usr/local"},
+ { "localstatedir", FR_CONF_POINTER(PW_TYPE_STRING, &localstatedir), "${prefix}/var"},
+ { "sbindir", FR_CONF_POINTER(PW_TYPE_STRING, &sbindir), "${prefix}/sbin"},
+ { "logdir", FR_CONF_POINTER(PW_TYPE_STRING, &radlog_dir), "${localstatedir}/log"},
+ { "run_dir", FR_CONF_POINTER(PW_TYPE_STRING, &run_dir), "${localstatedir}/run/${name}"},
+ { "libdir", FR_CONF_POINTER(PW_TYPE_STRING, &radlib_dir), "${prefix}/lib"},
+ { "radacctdir", FR_CONF_POINTER(PW_TYPE_STRING, &radacct_dir), "${logdir}/radacct" },
+ { "panic_action", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.panic_action), NULL},
+ { "hostname_lookups", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &fr_dns_lookups), "no" },
+ { "max_request_time", FR_CONF_POINTER(PW_TYPE_INTEGER, &main_config.max_request_time), STRINGIFY(MAX_REQUEST_TIME) },
+ { "cleanup_delay", FR_CONF_POINTER(PW_TYPE_INTEGER, &main_config.cleanup_delay), STRINGIFY(CLEANUP_DELAY) },
+ { "max_requests", FR_CONF_POINTER(PW_TYPE_INTEGER, &main_config.max_requests), STRINGIFY(MAX_REQUESTS) },
+ { "pidfile", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.pid_file), "${run_dir}/radiusd.pid"},
+ { "checkrad", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.checkrad), "${sbindir}/checkrad" },
+
+ { "debug_level", FR_CONF_POINTER(PW_TYPE_INTEGER, &main_config.debug_level), "0"},
#ifdef WITH_PROXY
- { "proxy_requests", PW_TYPE_BOOLEAN, 0, &mainconfig.proxy_requests, "yes" },
+ { "proxy_requests", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.proxy_requests), "yes" },
#endif
- { "log", PW_TYPE_SUBSECTION, 0, NULL, (void const *) log_config_nodest },
+ { "log", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) log_config_nodest },
/*
* People with old configs will have these. They are listed
* DON'T exist in radiusd.conf, then the previously parsed
* values for "log { foo = bar}" will be used.
*/
- { "log_auth", PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, 0, &mainconfig.log_auth, NULL },
- { "log_auth_badpass", PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, 0, &mainconfig.log_auth_badpass, NULL },
- { "log_auth_goodpass", PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, 0, &mainconfig.log_auth_goodpass, NULL },
- { "log_stripped_names", PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, 0, &log_stripped_names, NULL },
+ { "log_auth", FR_CONF_POINTER(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, &main_config.log_auth), NULL },
+ { "log_auth_badpass", FR_CONF_POINTER(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, &main_config.log_auth_badpass), NULL },
+ { "log_auth_goodpass", FR_CONF_POINTER(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, &main_config.log_auth_goodpass), NULL },
+ { "log_stripped_names", FR_CONF_POINTER(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, &log_stripped_names), NULL },
- { "security", PW_TYPE_SUBSECTION, 0, NULL, (void const *) security_config },
+ { "security", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) security_config },
{ NULL, -1, 0, NULL, NULL }
};
static const CONF_PARSER bootstrap_security_config[] = {
#ifdef HAVE_SETUID
- { "user", PW_TYPE_STRING_PTR, 0, &uid_name, NULL },
- { "group", PW_TYPE_STRING_PTR, 0, &gid_name, NULL },
+ { "user", FR_CONF_POINTER(PW_TYPE_STRING, &uid_name), NULL },
+ { "group", FR_CONF_POINTER(PW_TYPE_STRING, &gid_name), NULL },
#endif
- { "chroot", PW_TYPE_STRING_PTR, 0, &chroot_dir, NULL },
- { "allow_core_dumps", PW_TYPE_BOOLEAN, 0, &allow_core_dumps, "no" },
+ { "chroot", FR_CONF_POINTER(PW_TYPE_STRING, &chroot_dir), NULL },
+ { "allow_core_dumps", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &allow_core_dumps), "no" },
{ NULL, -1, 0, NULL, NULL }
};
static const CONF_PARSER bootstrap_config[] = {
- { "security", PW_TYPE_SUBSECTION, 0, NULL, (void const *) bootstrap_security_config },
+ { "security", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) bootstrap_security_config },
/*
* For backwards compatibility.
*/
#ifdef HAVE_SETUID
- { "user", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, 0, &uid_name, NULL },
- { "group", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, 0, &gid_name, NULL },
+ { "user", FR_CONF_POINTER(PW_TYPE_STRING | PW_TYPE_DEPRECATED, &uid_name), NULL },
+ { "group", FR_CONF_POINTER(PW_TYPE_STRING | PW_TYPE_DEPRECATED, &gid_name), NULL },
#endif
- { "chroot", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, 0, &chroot_dir, NULL },
- { "allow_core_dumps", PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, 0, &allow_core_dumps, NULL },
+ { "chroot", FR_CONF_POINTER(PW_TYPE_STRING | PW_TYPE_DEPRECATED, &chroot_dir), NULL },
+ { "allow_core_dumps", FR_CONF_POINTER(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, &allow_core_dumps), NULL },
{ NULL, -1, 0, NULL, NULL }
};
if (!fmt || !out || (outlen < 1)) return 0;
- if (!request || !request->client) {
+ if (!request->client) {
RWDEBUG("No client associated with this request");
*out = '\0';
return 0;
}
strlcpy(buffer, p, (q + 1) - p);
- if (ip_ptonx(buffer, &ip) <= 0) {
+ if (fr_pton(&ip, buffer, 0, false) <= 0) {
REDEBUG("\"%s\" is not a valid IPv4 or IPv6 address", buffer);
goto error;
}
return -1;
}
-#ifdef HAVE_SYS_RESOURCE_H
-static struct rlimit core_limits;
-#endif
-
-static void fr_set_dumpable(void)
-{
- /*
- * If configured, turn core dumps off.
- */
- if (!allow_core_dumps) {
-#ifdef HAVE_SYS_RESOURCE_H
- struct rlimit no_core;
-
-
- no_core.rlim_cur = 0;
- no_core.rlim_max = 0;
-
- if (setrlimit(RLIMIT_CORE, &no_core) < 0) {
- ERROR("Failed disabling core dumps: %s",
- strerror(errno));
- }
-#endif
- return;
- }
-
- /*
- * Set or re-set the dumpable flag.
- */
-#ifdef HAVE_SYS_PRCTL_H
-#ifdef PR_SET_DUMPABLE
- if (prctl(PR_SET_DUMPABLE, 1) < 0) {
- ERROR("Cannot re-enable core dumps: prctl(PR_SET_DUMPABLE) failed: '%s'",
- strerror(errno));
- }
-#endif
-#endif
-
- /*
- * Reset the core dump limits to their original value.
- */
-#ifdef HAVE_SYS_RESOURCE_H
- if (setrlimit(RLIMIT_CORE, &core_limits) < 0) {
- ERROR("Cannot update core dump limit: %s",
- strerror(errno));
- }
-#endif
-}
-
#ifdef HAVE_SETUID
-static int doing_setuid = false;
+static bool doing_setuid = false;
-#if defined(HAVE_SETRESUID) && defined (HAVE_GETRESUID)
+# if defined(HAVE_SETRESUID) && defined (HAVE_GETRESUID)
void fr_suid_up(void)
{
uid_t ruid, euid, suid;
if (setresuid(-1, server_uid, geteuid()) < 0) {
fprintf(stderr, "%s: Failed switching to uid %s: %s\n",
- progname, uid_name, strerror(errno));
+ progname, uid_name, fr_syserror(errno));
fr_exit_now(1);
}
fr_exit_now(1);
}
- fr_set_dumpable();
+ fr_set_dumpable(allow_core_dumps);
}
void fr_suid_down_permanent(void)
if (setresuid(server_uid, server_uid, server_uid) < 0) {
ERROR("Failed in permanent switch to uid %s: %s",
- uid_name, strerror(errno));
+ uid_name, fr_syserror(errno));
fr_exit_now(1);
}
fr_exit_now(1);
}
- fr_set_dumpable();
+ fr_set_dumpable(allow_core_dumps);
}
-#else
+# else
/*
* Much less secure...
*/
void fr_suid_up(void)
{
}
+
void fr_suid_down(void)
{
if (!uid_name) return;
if (setuid(server_uid) < 0) {
fprintf(stderr, "%s: Failed switching to uid %s: %s\n",
- progname, uid_name, strerror(errno));
+ progname, uid_name, fr_syserror(errno));
fr_exit(1);
}
- fr_set_dumpable();
+ fr_set_dumpable(allow_core_dumps);
}
+
void fr_suid_down_permanent(void)
{
- fr_set_dumpable();
+ fr_set_dumpable(allow_core_dumps);
}
-#endif /* HAVE_SETRESUID && HAVE_GETRESUID */
+# endif /* HAVE_SETRESUID && HAVE_GETRESUID */
#else /* HAVE_SETUID */
void fr_suid_up(void)
{
}
void fr_suid_down(void)
{
- fr_set_dumpable();
+ fr_set_dumpable(allow_core_dumps);
}
void fr_suid_down_permanent(void)
{
- fr_set_dumpable();
+ fr_set_dumpable(allow_core_dumps);
}
#endif /* HAVE_SETUID */
*/
static int switch_users(CONF_SECTION *cs)
{
-#ifdef HAVE_SYS_RESOURCE_H
/*
* Get the current maximum for core files. Do this
* before anything else so as to ensure it's properly
* initialized.
*/
- if (getrlimit(RLIMIT_CORE, &core_limits) < 0) {
- ERROR("Failed to get current core limit: %s", strerror(errno));
+ if (fr_set_dumpable_init() < 0) {
+ fr_perror("radiusd");
return 0;
}
-#endif
/*
* Don't do chroot/setuid/setgid if we're in debugging
gr = getgrnam(gid_name);
if (gr == NULL) {
fprintf(stderr, "%s: Cannot get ID for group %s: %s\n",
- progname, gid_name, strerror(errno));
+ progname, gid_name, fr_syserror(errno));
return 0;
}
server_gid = gr->gr_gid;
pw = getpwnam(uid_name);
if (pw == NULL) {
fprintf(stderr, "%s: Cannot get passwd entry for user %s: %s\n",
- progname, uid_name, strerror(errno));
+ progname, uid_name, fr_syserror(errno));
return 0;
}
#ifdef HAVE_INITGROUPS
if (initgroups(uid_name, server_gid) < 0) {
fprintf(stderr, "%s: Cannot initialize supplementary group list for user %s: %s\n",
- progname, uid_name, strerror(errno));
+ progname, uid_name, fr_syserror(errno));
return 0;
}
#endif
if (chroot_dir) {
if (chroot(chroot_dir) < 0) {
fprintf(stderr, "%s: Failed to perform chroot %s: %s",
- progname, chroot_dir, strerror(errno));
+ progname, chroot_dir, fr_syserror(errno));
return 0;
}
/* Set GID. */
if (gid_name && (setgid(server_gid) < 0)) {
fprintf(stderr, "%s: Failed setting group to %s: %s",
- progname, gid_name, strerror(errno));
+ progname, gid_name, fr_syserror(errno));
return 0;
}
#endif
* specified on the command-line.
*/
if (uid_name || gid_name) {
- if ((default_log.dest == L_DST_FILES) &&
+ if ((default_log.dst == L_DST_FILES) &&
(default_log.fd < 0)) {
- default_log.fd = open(mainconfig.log_file,
+ default_log.fd = open(main_config.log_file,
O_WRONLY | O_APPEND | O_CREAT, 0640);
if (default_log.fd < 0) {
- fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", mainconfig.log_file, strerror(errno));
+ fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", main_config.log_file, fr_syserror(errno));
return 0;
}
- if (chown(mainconfig.log_file, server_uid, server_gid) < 0) {
+ if (chown(main_config.log_file, server_uid, server_gid) < 0) {
fprintf(stderr, "%s: Cannot change ownership of log file %s: %s\n",
- progname, mainconfig.log_file, strerror(errno));
+ progname, main_config.log_file, fr_syserror(errno));
return 0;
}
}
* This also clears the dumpable flag if core dumps
* aren't allowed.
*/
- fr_set_dumpable();
+ if (fr_set_dumpable(allow_core_dumps) < 0) {
+ ERROR("%s", fr_strerror());
+ }
if (allow_core_dumps) {
- INFO("Core dumps are enabled.");
+ INFO("Core dumps are enabled");
}
return 1;
}
#endif /* HAVE_SETUID */
+/** Set the global radius config directory.
+ *
+ * @param ctx Where to allocate the memory for the path string.
+ * @param path to config dir root e.g. /usr/local/etc/raddb
+ */
+void set_radius_dir(TALLOC_CTX *ctx, char const *path)
+{
+ if (radius_dir) {
+ char *p;
+
+ memcpy(&p, &radius_dir, sizeof(p));
+ talloc_free(p);
+ radius_dir = NULL;
+ }
+ if (path) radius_dir = talloc_strdup(ctx, path);
+}
+
+/** Get the global radius config directory.
+ *
+ * @return the global radius config directory.
+ */
+char const *get_radius_dir(void)
+{
+ return radius_dir;
+}
/*
* Read config files.
*
* This function can ONLY be called from the main server process.
*/
-int read_mainconfig(int reload)
+int main_config_init(void)
{
char const *p = NULL;
CONF_SECTION *cs;
cached_config_t *cc;
char buffer[1024];
- if (reload != 0) {
- ERROR("Reload is not implemented");
- return -1;
- }
-
if (stat(radius_dir, &statbuf) < 0) {
ERROR("Errors reading %s: %s",
- radius_dir, strerror(errno));
+ radius_dir, fr_syserror(errno));
return -1;
}
#endif
INFO("Starting - reading configuration files ...");
- /* Initialize the dictionary */
- if (!mainconfig.dictionary_dir) mainconfig.dictionary_dir = radius_dir;
- DEBUG2("including dictionary file %s/%s", mainconfig.dictionary_dir, RADIUS_DICTIONARY);
- if (dict_init(mainconfig.dictionary_dir, RADIUS_DICTIONARY) != 0) {
+ /*
+ * We need to load the dictionaries before reading the
+ * configuration files. This is because of the
+ * pre-compilation in conffile.c. That should probably
+ * be fixed to be done as a second stage.
+ */
+ if (!main_config.dictionary_dir) {
+ main_config.dictionary_dir = DICTDIR;
+ }
+
+ /*
+ * Read the distribution dictionaries first, then
+ * the ones in raddb.
+ */
+ DEBUG2("including dictionary file %s/%s", main_config.dictionary_dir, RADIUS_DICTIONARY);
+ if (dict_init(main_config.dictionary_dir, RADIUS_DICTIONARY) != 0) {
ERROR("Errors reading dictionary: %s",
- fr_strerror());
+ fr_strerror());
return -1;
}
+#define DICT_READ_OPTIONAL(_d, _n) \
+do {\
+ switch (dict_read(_d, _n)) {\
+ case -1:\
+ ERROR("Errors reading %s/%s: %s", _d, _n, fr_strerror());\
+ return -1;\
+ case 0:\
+ DEBUG2("including dictionary file %s/%s", _d,_n);\
+ break;\
+ default:\
+ break;\
+ }\
+} while (0)
+
+ /*
+ * Try to load protocol-specific dictionaries. It's OK
+ * if they don't exist.
+ */
+#ifdef WITH_DHCP
+ DICT_READ_OPTIONAL(main_config.dictionary_dir, "dictionary.dhcp");
+#endif
+
+#ifdef WITH_VMPS
+ DICT_READ_OPTIONAL(main_config.dictionary_dir, "dictionary.vqp");
+#endif
+
+ /*
+ * It's OK if this one doesn't exist.
+ */
+ DICT_READ_OPTIONAL(radius_dir, RADIUS_DICTIONARY);
+
/* Read the configuration file */
snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf",
- radius_dir, mainconfig.name);
+ radius_dir, main_config.name);
if ((cs = cf_file_read(buffer)) == NULL) {
ERROR("Errors reading or parsing %s", buffer);
return -1;
* If there was no log destination set on the command line,
* set it now.
*/
- if (default_log.dest == L_DST_NULL) {
+ if (default_log.dst == L_DST_NULL) {
if (cf_section_parse(cs, NULL, serverdest_config) < 0) {
fprintf(stderr, "radiusd: Error: Failed to parse log{} section.\n");
cf_file_free(cs);
return -1;
}
- default_log.dest = fr_str2int(log_str2dst, radlog_dest,
+ default_log.dst = fr_str2int(log_str2dst, radlog_dest,
L_DST_NUM_DEST);
- if (default_log.dest == L_DST_NUM_DEST) {
+ if (default_log.dst == L_DST_NUM_DEST) {
fprintf(stderr, "radiusd: Error: Unknown log_destination %s\n",
radlog_dest);
cf_file_free(cs);
return -1;
}
- if (default_log.dest == L_DST_SYSLOG) {
+ if (default_log.dst == L_DST_SYSLOG) {
/*
* Make sure syslog_facility isn't NULL
* before using it
cf_file_free(cs);
return -1;
}
- mainconfig.syslog_facility = fr_str2int(syslog_str2fac, syslog_facility, -1);
- if (mainconfig.syslog_facility < 0) {
+ main_config.syslog_facility = fr_str2int(syslog_str2fac, syslog_facility, -1);
+ if (main_config.syslog_facility < 0) {
fprintf(stderr, "radiusd: Error: Unknown syslog_facility %s\n",
syslog_facility);
cf_file_free(cs);
* Call openlog only once, when the
* program starts.
*/
- openlog(progname, LOG_PID, mainconfig.syslog_facility);
+ openlog(progname, LOG_PID, main_config.syslog_facility);
#endif
- } else if (default_log.dest == L_DST_FILES) {
- if (!mainconfig.log_file) {
+ } else if (default_log.dst == L_DST_FILES) {
+ if (!main_config.log_file) {
fprintf(stderr, "radiusd: Error: Specified \"files\" as a log destination, but no log filename was given!\n");
cf_file_free(cs);
return -1;
* did switch uid/gid, then the code in switch_users()
* took care of setting the file permissions correctly.
*/
- if ((default_log.dest == L_DST_FILES) &&
+ if ((default_log.dst == L_DST_FILES) &&
(default_log.fd < 0)) {
- default_log.fd = open(mainconfig.log_file,
+ default_log.fd = open(main_config.log_file,
O_WRONLY | O_APPEND | O_CREAT, 0640);
if (default_log.fd < 0) {
- fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", mainconfig.log_file, strerror(errno));
+ fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", main_config.log_file, fr_syserror(errno));
cf_file_free(cs);
return -1;
}
default_log.colourise = false;
}
- if (mainconfig.max_request_time == 0) mainconfig.max_request_time = 100;
- if (mainconfig.reject_delay > 5) mainconfig.reject_delay = 5;
- if (mainconfig.cleanup_delay > 5) mainconfig.cleanup_delay =5;
+ /*
+ * Starting the server, WITHOUT "-x" on the
+ * command-line: use whatever is in the config
+ * file.
+ */
+ if (debug_flag == 0) {
+ debug_flag = main_config.debug_level;
+ }
+ fr_debug_flag = debug_flag;
+
+ FR_INTEGER_COND_CHECK("max_request_time", main_config.max_request_time, (main_config.max_request_time != 0), 100);
+ FR_INTEGER_BOUND_CHECK("reject_delay", main_config.reject_delay, <=, 10);
+ FR_INTEGER_BOUND_CHECK("cleanup_delay", main_config.cleanup_delay, <=, 10);
+
+ /*
+ * Set default initial request processing delay to 1/3 of a second.
+ * Will be updated by the lowest response window across all home servers,
+ * if it is less than this.
+ */
+ main_config.init_delay.tv_sec = 0;
+ main_config.init_delay.tv_usec = 1000000 / 3;
/*
* Free the old configuration items, and replace them
* Note that where possible, we do atomic switch-overs,
* to ensure that the pointers are always valid.
*/
- rad_assert(mainconfig.config == NULL);
- root_config = mainconfig.config = cs;
+ rad_assert(main_config.config == NULL);
+ root_config = main_config.config = cs;
- DEBUG2("%s: #### Loading Realms and Home Servers ####", mainconfig.name);
+ DEBUG2("%s: #### Loading Realms and Home Servers ####", main_config.name);
if (!realms_init(cs)) {
return -1;
}
- DEBUG2("%s: #### Loading Clients ####", mainconfig.name);
+ DEBUG2("%s: #### Loading Clients ####", main_config.name);
if (!clients_parse_section(cs, false)) {
return -1;
}
xlat_register("getclient", xlat_getclient, NULL, NULL);
/*
- * Starting the server, WITHOUT "-x" on the
- * command-line: use whatever is in the config
- * file.
- */
- if (debug_flag == 0) {
- debug_flag = mainconfig.debug_level;
- }
- fr_debug_flag = debug_flag;
-
- /*
* Go update our behaviour, based on the configuration
* changes.
*/
* Sanity check the configuration for internal
* consistency.
*/
- if (mainconfig.reject_delay > mainconfig.cleanup_delay) {
- mainconfig.reject_delay = mainconfig.cleanup_delay;
- }
- if (mainconfig.reject_delay < 0) mainconfig.reject_delay = 0;
-
- /* Reload the modules. */
- if (setup_modules(reload, mainconfig.config) < 0) {
- return -1;
- }
+ FR_INTEGER_BOUND_CHECK("reject_delay", main_config.reject_delay, <=, main_config.cleanup_delay);
if (chroot_dir) {
if (chdir(radlog_dir) < 0) {
ERROR("Failed to 'chdir %s' after chroot: %s",
- radlog_dir, strerror(errno));
+ radlog_dir, fr_syserror(errno));
return -1;
}
}
- cc = rad_malloc(sizeof(*cc));
- memset(cc, 0, sizeof(*cc));
+ cc = talloc_zero(NULL, cached_config_t);
+ if (!cc) return -1;
- cc->cs = cs;
+ cc->cs = talloc_steal(cc ,cs);
rad_assert(cs_cache == NULL);
cs_cache = cc;
+ /* Clear any unprocessed configuration errors */
+ (void) fr_strerror();
+
return 0;
}
/*
* Free the configuration. Called only when the server is exiting.
*/
-int free_mainconfig(void)
+int main_config_free(void)
{
- cached_config_t *cc, *next;
-
virtual_servers_free(0);
/*
*/
clients_free(NULL);
realms_free();
- listen_free(&mainconfig.listen);
+ listen_free(&main_config.listen);
/*
- * Free all of the cached configurations.
+ * Frees current config and any previous configs.
*/
- for (cc = cs_cache; cc != NULL; cc = next) {
- next = cc->next;
- cf_file_free(cc->cs);
- free(cc);
- }
-
+ TALLOC_FREE(cs_cache);
dict_free();
return 0;
{
int fd, old_fd;
- if (default_log.dest != L_DST_FILES) return;
+ if (default_log.dst != L_DST_FILES) return;
- fd = open(mainconfig.log_file,
+ fd = open(main_config.log_file,
O_WRONLY | O_APPEND | O_CREAT, 0640);
if (fd >= 0) {
/*
}
}
-void hup_mainconfig(void)
+void main_config_hup(void)
{
cached_config_t *cc;
CONF_SECTION *cs;
/* Read the configuration file */
snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf",
- radius_dir, mainconfig.name);
+ radius_dir, main_config.name);
if ((cs = cf_file_read(buffer)) == NULL) {
ERROR("Failed to re-read or parse %s", buffer);
return;
}
- cc = rad_malloc(sizeof(*cc));
- memset(cc, 0, sizeof(*cc));
+ cc = talloc_zero(cs_cache, cached_config_t);
+ if (!cc) {
+ ERROR("Out of memory");
+ return;
+ }
/*
* Save the current configuration. Note that we do NOT
* configurations.
*/
cc->created = time(NULL);
- cc->cs = cs;
+ cc->cs = talloc_steal(cc, cs);
cc->next = cs_cache;
cs_cache = cc;
/*
* Prefer the new module configuration.
*/
- module_hup(cf_section_sub_find(cs, "modules"));
+ modules_hup(cf_section_sub_find(cs, "modules"));
/*
* Load new servers BEFORE freeing old ones.
*/
virtual_servers_load(cs);
- virtual_servers_free(cc->created - mainconfig.max_request_time * 4);
+ virtual_servers_free(cc->created - main_config.max_request_time * 4);
}
{
if (*tmpl == NULL) return;
- dict_attr_free(&((*tmpl)->da));
+ dict_attr_free(&((*tmpl)->vpt_da));
talloc_free(*tmpl);
* string might be freed before you're done with the vpt use radius_attr2tmpl
* instead.
*
- * @param[in] name attribute name including qualifiers.
+ * The special return code of -2 is used only by radius_str2tmpl, which allow
+ * bare words which might (or might not) be an attribute reference.
+ *
* @param[out] vpt to modify.
- * @param[in] request_def The default request to insert unqualified
- * attributes into.
+ * @param[in] name attribute name including qualifiers.
+ * @param[in] request_def The default request to insert unqualified attributes into.
* @param[in] list_def The default list to insert unqualified attributes into.
- * @return -1 on error or 0 on success.
+ * @return -2 on partial parse followed by error, -1 on other error, or 0 on success
*/
-int radius_parse_attr(char const *name, value_pair_tmpl_t *vpt,
- request_refs_t request_def,
- pair_lists_t list_def)
+int radius_parse_attr(value_pair_tmpl_t *vpt, char const *name, request_refs_t request_def, pair_lists_t list_def)
{
- DICT_ATTR const *da;
+ int error = -1;
char const *p;
size_t len;
+ unsigned long num;
+ char *q;
+ DICT_ATTR const *da;
memset(vpt, 0, sizeof(*vpt));
vpt->name = name;
p = name;
- vpt->request = radius_request_name(&p, request_def);
+ if (*p == '&') {
+ error = -2;
+ p++;
+ }
+
+ vpt->vpt_request = radius_request_name(&p, request_def);
len = p - name;
- if (vpt->request == REQUEST_UNKNOWN) {
- ERROR("Invalid request qualifier \"%.*s\"", (int) len, name);
- return -1;
+ if (vpt->vpt_request == REQUEST_UNKNOWN) {
+ fr_strerror_printf("Invalid request qualifier \"%.*s\"", (int) len, name);
+ return error;
}
name += len;
- vpt->list = radius_list_name(&p, list_def);
- if (vpt->list == PAIR_LIST_UNKNOWN) {
+ vpt->vpt_list = radius_list_name(&p, list_def);
+ if (vpt->vpt_list == PAIR_LIST_UNKNOWN) {
len = p - name;
- ERROR("Invalid list qualifier \"%.*s\"", (int) len, name);
- return -1;
+ fr_strerror_printf("Invalid list qualifier \"%.*s\"", (int) len, name);
+ return error;
}
if (*p == '\0') {
return 0;
}
- da = dict_attrbyname(p);
+ da = dict_attrbytagged_name(p);
if (!da) {
da = dict_attrunknownbyname(p, false);
if (!da) {
- ERROR("Unknown attribute \"%s\"", p);
- return -1;
+ fr_strerror_printf("Unknown attribute \"%s\"", p);
+ return error;
}
}
- vpt->da = da;
-
+ vpt->vpt_da = da;
vpt->type = VPT_TYPE_ATTR;
+ vpt->vpt_tag = TAG_ANY;
+ vpt->vpt_num = NUM_ANY;
+
+ /*
+ * After this point, we return -2 to indicate that parts
+ * of the string were parsed as an attribute, but others
+ * weren't.
+ */
+ while (*p) {
+ if (*p == ':') break;
+ if (*p == '[') break;
+ p++;
+ }
+
+ if (*p == ':') {
+ if (!da->flags.has_tag) {
+ fr_strerror_printf("Attribute '%s' cannot have a tag", da->name);
+ return -2;
+ }
+
+ num = strtoul(p + 1, &q, 10);
+ if (num > 0x1f) {
+ fr_strerror_printf("Invalid tag value '%u' (should be between 0-31)", (unsigned int) num);
+ return -2;
+ }
+
+ vpt->vpt_tag = num;
+ p = q;
+ }
+
+ if (!*p) return 0;
+
+ if (*p != '[') {
+ fr_strerror_printf("Unexpected text after tag in '%s'", name);
+ return -2;
+ }
+
+ num = strtoul(p + 1, &q, 10);
+ if (num > 1000) {
+ fr_strerror_printf("Invalid array reference '%u' (should be between 0-1000)", (unsigned int) num);
+ return -2;
+ }
+
+ if ((*q != ']') || (q[1] != '\0')) {
+ fr_strerror_printf("Unexpected text after array in '%s'", name);
+ return -2;
+ }
+
+ vpt->vpt_num = num;
+
return 0;
}
char const *copy;
vpt = talloc(ctx, value_pair_tmpl_t); /* parse_attr zeroes it */
- copy = talloc_strdup(vpt, name);
+ copy = talloc_typed_strdup(vpt, name);
- if (radius_parse_attr(copy, vpt, request_def, list_def) < 0) {
+ if (radius_parse_attr(vpt, copy, request_def, list_def) < 0) {
+ ERROR("%s", fr_strerror());
radius_tmplfree(&vpt);
return NULL;
}
* @param[in] ctx for talloc
* @param[in] name string to convert.
* @param[in] type Type of quoting around value.
+ * @param[in] request_def The default request to insert unqualified
+ * attributes into.
+ * @param[in] list_def The default list to insert unqualified attributes into.
* @return pointer to new VPT.
*/
-value_pair_tmpl_t *radius_str2tmpl(TALLOC_CTX *ctx, char const *name, FR_TOKEN type)
+value_pair_tmpl_t *radius_str2tmpl(TALLOC_CTX *ctx, char const *name, FR_TOKEN type,
+ request_refs_t request_def, pair_lists_t list_def)
{
+ int rcode;
+ char const *p;
value_pair_tmpl_t *vpt;
+ char buffer[1024];
vpt = talloc_zero(ctx, value_pair_tmpl_t);
- vpt->name = talloc_strdup(vpt, name);
+ vpt->name = talloc_typed_strdup(vpt, name);
switch (type) {
case T_BARE_WORD:
- if (*name == '&') name++;
-
- if (!isdigit((int) *name)) {
- request_refs_t ref;
- pair_lists_t list;
- char const *p = name;
-
- ref = radius_request_name(&p, REQUEST_CURRENT);
- if (ref == REQUEST_UNKNOWN) goto literal;
-
- list = radius_list_name(&p, PAIR_LIST_REQUEST);
- if (list == PAIR_LIST_UNKNOWN) goto literal;
-
- if ((p != name) && !*p) {
- vpt->type = VPT_TYPE_LIST;
-
- } else {
- DICT_ATTR const *da;
- da = dict_attrbyname(p);
- if (!da) {
- vpt->type = VPT_TYPE_LITERAL;
- break;
- }
- vpt->da = da;
- vpt->type = VPT_TYPE_ATTR;
- }
-
- vpt->request = ref;
- vpt->list = list;
+ /*
+ * If we can parse it as an attribute, it's an attribute.
+ * Otherwise, treat it as a literal.
+ */
+ rcode = radius_parse_attr(vpt, vpt->name, request_def, list_def);
+ if (rcode == -2) {
+ talloc_free(vpt);
+ return NULL;
+ }
+ if (rcode == 0) {
break;
}
/* FALL-THROUGH */
case T_SINGLE_QUOTED_STRING:
- literal:
vpt->type = VPT_TYPE_LITERAL;
break;
+
case T_DOUBLE_QUOTED_STRING:
- vpt->type = VPT_TYPE_XLAT;
+ p = name;
+ while (*p) {
+ if (*p == '\\') {
+ if (!p[1]) break;
+ p += 2;
+ continue;
+ }
+
+ if (*p == '%') break;
+
+ p++;
+ }
+
+ /*
+ * If the double quoted string needs to be
+ * expanded at run time, make it an xlat
+ * expansion. Otherwise, convert it to be a
+ * literal.
+ */
+ if (*p) {
+ vpt->type = VPT_TYPE_XLAT;
+ } else {
+ vpt->type = VPT_TYPE_LITERAL;
+ }
break;
+
case T_BACK_QUOTED_STRING:
vpt->type = VPT_TYPE_EXEC;
break;
+
case T_OP_REG_EQ: /* hack */
vpt->type = VPT_TYPE_REGEX;
break;
+
default:
rad_assert(0);
return NULL;
}
+ radius_tmpl2str(buffer, sizeof(buffer), vpt);
+
return vpt;
}
-/** Convert strings to value_pair_map_e
+/** Convert strings to value_pair_map_t
*
* Treatment of operands depends on quotation, barewords are treated
* as attribute references, double quoted values are treated as
map = talloc_zero(ctx, value_pair_map_t);
- if ((lhs_type == T_BARE_WORD) && (*lhs == '&')) {
- map->dst = radius_attr2tmpl(map, lhs + 1, dst_request_def, dst_list_def);
- } else {
- map->dst = radius_str2tmpl(map, lhs, lhs_type);
- }
-
+ map->dst = radius_str2tmpl(map, lhs, lhs_type, dst_request_def, dst_list_def);
if (!map->dst) {
error:
talloc_free(map);
map->op = op;
- /*
- * Ignore the RHS if it's a true / false comparison.
- */
- if ((map->op == T_OP_CMP_TRUE) || (map->op == T_OP_CMP_FALSE)) {
- return map;
- }
-
- if ((rhs_type == T_BARE_WORD) && (*rhs == '&')) {
- map->src = radius_attr2tmpl(map, rhs + 1, src_request_def, src_list_def);
- } else {
- map->src = radius_str2tmpl(map, rhs, rhs_type);
- }
-
- if (!map->dst) goto error;
+ map->src = radius_str2tmpl(map, rhs, rhs_type, src_request_def, src_list_def);
+ if (!map->src) goto error;
return map;
}
if (!cp) return NULL;
map = talloc_zero(ctx, value_pair_map_t);
+ map->op = cf_pair_operator(cp);
+ map->ci = ci;
attr = cf_pair_attr(cp);
value = cf_pair_value(cp);
goto error;
}
+ /*
+ * LHS must always be an attribute reference.
+ */
map->dst = radius_attr2tmpl(map, attr, dst_request_def, dst_list_def);
if (!map->dst) {
cf_log_err(ci, "Syntax error in attribute definition");
}
/*
- * Bare words always mean attribute references.
+ * RHS might be an attribute reference.
*/
type = cf_pair_value_type(cp);
- if (type == T_BARE_WORD) {
- if (*value == '&') {
- map->src = radius_attr2tmpl(map, value + 1, src_request_def, src_list_def);
- } else {
- if (!isdigit((int) *value) &&
- ((strchr(value, ':') != NULL) ||
- (dict_attrbyname(value) != NULL))) {
- map->src = radius_attr2tmpl(map, value, src_request_def, src_list_def);
- }
- if (map->src) {
- WDEBUG("%s[%d]: Please add '&' for attribute reference '%s = &%s'",
- cf_pair_filename(cp), cf_pair_lineno(cp),
- attr, value);
- } else {
- map->src = radius_str2tmpl(map, value, type);
- }
- }
- } else {
- map->src = radius_str2tmpl(map, value, type);
- }
-
+ map->src = radius_str2tmpl(map, value, type, src_request_def, src_list_def);
if (!map->src) {
goto error;
}
- map->op = cf_pair_operator(cp);
- map->ci = ci;
+ /*
+ * Anal-retentive checks.
+ */
+ if (debug_flag > 2) {
+ if ((map->dst->type == VPT_TYPE_ATTR) && (*attr != '&')) {
+ WARN("%s[%d]: Please change attribute reference to '&%s %s ...'",
+ cf_pair_filename(cp), cf_pair_lineno(cp),
+ attr, fr_int2str(fr_tokens, map->op, "<INVALID>"));
+ }
+
+ if ((map->src->type == VPT_TYPE_ATTR) && (*value != '&')) {
+ WARN("%s[%d]: Please change attribute reference to '... %s &%s'",
+ cf_pair_filename(cp), cf_pair_lineno(cp),
+ fr_int2str(fr_tokens, map->op, "<INVALID>"), value);
+ }
+ }
+
+ /*
+ * Values used by unary operators should be literal ANY
+ *
+ * We then free the template and alloc a NULL one instead.
+ */
+ if (map->op == T_OP_CMP_FALSE) {
+ if ((map->src->type != VPT_TYPE_LITERAL) || (strcmp(map->src->name, "ANY") != 0)) {
+ WARN("%s[%d] Wildcard deletion MUST use '!* ANY'", cf_pair_filename(cp), cf_pair_lineno(cp));
+ }
+
+ radius_tmplfree(&map->src);
+
+ map->src = talloc_zero(map, value_pair_tmpl_t);
+ map->src->type = VPT_TYPE_NULL;
+ }
/*
* Lots of sanity checks for insane people...
* We don't support implicit type conversion,
* except for "octets"
*/
- if (map->dst->da && map->src->da &&
- (map->src->da->type != map->dst->da->type) &&
- (map->src->da->type != PW_TYPE_OCTETS) &&
- (map->dst->da->type != PW_TYPE_OCTETS)) {
+ if (map->dst->vpt_da && map->src->vpt_da &&
+ (map->src->vpt_da->type != map->dst->vpt_da->type) &&
+ (map->src->vpt_da->type != PW_TYPE_OCTETS) &&
+ (map->dst->vpt_da->type != PW_TYPE_OCTETS)) {
cf_log_err(ci, "Attribute type mismatch");
goto error;
}
}
/*
- * Can't copy an xlat expansion or literal into a list,
- * we don't know what type of attribute we'd need
- * to create
- */
- if ((map->dst->type == VPT_TYPE_LIST) &&
- ((map->src->type == VPT_TYPE_XLAT) || (map->src->type == VPT_TYPE_LITERAL))) {
- cf_log_err(ci, "Can't copy value into list (we don't know which attribute to create)");
- goto error;
- }
-
- /*
* Depending on the attribute type, some operators are
* disallowed.
*/
if (map->dst->type == VPT_TYPE_ATTR) {
- if ((map->op != T_OP_EQ) &&
- (map->op != T_OP_CMP_EQ) &&
- (map->op != T_OP_ADD) &&
- (map->op != T_OP_SUB) &&
- (map->op != T_OP_LE) &&
- (map->op != T_OP_GE) &&
- (map->op != T_OP_CMP_FALSE) &&
- (map->op != T_OP_SET)) {
+ switch (map->op) {
+ default:
cf_log_err(ci, "Invalid operator for attribute");
goto error;
+
+ case T_OP_EQ:
+ case T_OP_CMP_EQ:
+ case T_OP_ADD:
+ case T_OP_SUB:
+ case T_OP_LE:
+ case T_OP_GE:
+ case T_OP_CMP_FALSE:
+ case T_OP_SET:
+ break;
}
}
- switch (map->src->type) {
+ if (map->dst->type == VPT_TYPE_LIST) {
/*
- * Only += and -= operators are supported for list copy.
+ * Only += and :=, and !* operators are supported
+ * for lists.
*/
- case VPT_TYPE_LIST:
- switch (map->op) {
- case T_OP_SUB:
- case T_OP_ADD:
+ switch (map->op) {
+ case T_OP_CMP_FALSE:
+ break;
+
+ case T_OP_ADD:
+ if ((map->src->type != VPT_TYPE_LIST) &&
+ (map->src->type != VPT_TYPE_EXEC)) {
+ cf_log_err(ci, "Invalid source for list '+='");
+ goto error;
+ }
+ break;
+
+ case T_OP_SET:
+ if (map->src->type == VPT_TYPE_EXEC) {
+ WARN("%s[%d] Please change ':=' to '=' for list assignment",
+ cf_pair_filename(cp), cf_pair_lineno(cp));
break;
+ }
- default:
- cf_log_err(ci, "Operator \"%s\" not allowed "
- "for list copy",
- fr_int2str(fr_tokens, map->op, "<INVALID>"));
+ if (map->src->type != VPT_TYPE_LIST) {
+ cf_log_err(ci, "Invalid source for ':=' operator");
goto error;
}
- break;
+ break;
- default:
+ case T_OP_EQ:
+ if (map->src->type != VPT_TYPE_EXEC) {
+ cf_log_err(ci, "Invalid source for '=' operator");
+ goto error;
+ }
break;
+
+ default:
+ cf_log_err(ci, "Operator \"%s\" not allowed for list assignment",
+ fr_int2str(fr_tokens, map->op, "<INVALID>"));
+ goto error;
+ }
}
return map;
return 0;
error:
- talloc_free(*head);
+ TALLOC_FREE(*head);
return -1;
}
*/
size_t radius_tmpl2str(char *buffer, size_t bufsize, value_pair_tmpl_t const *vpt)
{
+ size_t len;
char c;
char const *p;
char *q = buffer;
char *end;
+ if (!vpt) {
+ *buffer = '\0';
+ return 0;
+ }
+
switch (vpt->type) {
default:
return 0;
case VPT_TYPE_REGEX:
+ case VPT_TYPE_REGEX_STRUCT:
c = '/';
break;
case VPT_TYPE_XLAT:
+ case VPT_TYPE_XLAT_STRUCT:
c = '"';
break;
+ case VPT_TYPE_LIST:
case VPT_TYPE_LITERAL: /* single-quoted or bare word */
/*
* Hack
case VPT_TYPE_ATTR:
buffer[0] = '&';
- if (vpt->request == REQUEST_CURRENT) {
- if (vpt->list == PAIR_LIST_REQUEST) {
- strlcpy(buffer + 1, vpt->da->name, bufsize - 1);
+ if (vpt->vpt_request == REQUEST_CURRENT) {
+ if (vpt->vpt_list == PAIR_LIST_REQUEST) {
+ strlcpy(buffer + 1, vpt->vpt_da->name, bufsize - 1);
} else {
snprintf(buffer + 1, bufsize - 1, "%s:%s",
- fr_int2str(pair_lists, vpt->list, ""),
- vpt->da->name);
+ fr_int2str(pair_lists, vpt->vpt_list, ""),
+ vpt->vpt_da->name);
}
} else {
snprintf(buffer + 1, bufsize - 1, "%s.%s:%s",
- fr_int2str(request_refs, vpt->request, ""),
- fr_int2str(pair_lists, vpt->list, ""),
- vpt->da->name);
+ fr_int2str(request_refs, vpt->vpt_request, ""),
+ fr_int2str(pair_lists, vpt->vpt_list, ""),
+ vpt->vpt_da->name);
+ }
+
+ len = strlen(buffer);
+
+ if ((vpt->vpt_tag == TAG_ANY) && (vpt->vpt_num == NUM_ANY)) {
+ return len;
+ }
+
+ q = buffer + len;
+ bufsize -= len;
+
+ if (vpt->vpt_tag != TAG_ANY) {
+ snprintf(q, bufsize, ":%d", vpt->vpt_tag);
+ len = strlen(q);
+ q += len;
+ bufsize -= len;
+ }
+
+ if (vpt->vpt_num != NUM_ANY) {
+ snprintf(q, bufsize, "[%u]", vpt->vpt_num);
+ len = strlen(q);
+ q += len;
}
- return strlen(buffer);
+
+ return (q - buffer);
case VPT_TYPE_DATA:
- {
+ if (vpt->vpt_value) {
VALUE_PAIR *vp;
TALLOC_CTX *ctx;
memcpy(&ctx, &vpt, sizeof(ctx)); /* hack */
- vp = pairalloc(ctx, vpt->da);
- memcpy(&vp->data, vpt->vpd, sizeof(vp->data));
- vp->length = vpt->length;
+ MEM(vp = pairalloc(ctx, vpt->vpt_da));
+ memcpy(&vp->data, vpt->vpt_value, sizeof(vp->data));
+ vp->length = vpt->vpt_length;
- q = vp_aprint(vp, vp);
+ q = vp_aprint_value(vp, vp);
- if ((vpt->da->type != PW_TYPE_STRING) &&
- (vpt->da->type != PW_TYPE_DATE)) {
+ if ((vpt->vpt_da->type != PW_TYPE_STRING) &&
+ (vpt->vpt_da->type != PW_TYPE_DATE)) {
strlcpy(buffer, q, bufsize);
} else {
/*
talloc_free(q);
pairfree(&vp);
return strlen(buffer);
+
+ } else {
+ *buffer = '\0';
+ return 0;
}
}
while (*p && (q < end)) {
if (*p == c) {
- if ((q - end) < 4) goto no_room; /* escape, char, quote, EOS */
+ if ((end - q) < 4) goto no_room; /* escape, char, quote, EOS */
*(q++) = '\\';
*(q++) = *(p++);
continue;
switch (*p) {
case '\\':
- if ((q - end) < 4) goto no_room;
+ if ((end - q) < 4) goto no_room;
*(q++) = '\\';
*(q++) = *(p++);
break;
case '\r':
- if ((q - end) < 4) goto no_room;
+ if ((end - q) < 4) goto no_room;
*(q++) = '\\';
*(q++) = 'r';
p++;
break;
case '\n':
- if ((q - end) < 4) goto no_room;
+ if ((end - q) < 4) goto no_room;
*(q++) = '\\';
*(q++) = 'r';
p++;
break;
case '\t':
- if ((q - end) < 4) goto no_room;
+ if ((end - q) < 4) goto no_room;
*(q++) = '\\';
*(q++) = 't';
p++;
rad_assert(map->src != NULL);
if ((map->dst->type == VPT_TYPE_ATTR) &&
- (map->dst->da->type == PW_TYPE_STRING) &&
+ (map->dst->vpt_da->type == PW_TYPE_STRING) &&
(map->src->type == VPT_TYPE_LITERAL)) {
*(p++) = '\'';
len = radius_tmpl2str(p, end - p, map->src);
return p - buffer;
}
+
+/** Cast a literal vpt to a value_data_t
+ *
+ * @param[in,out] vpt the template to modify
+ * @param[in] da the dictionary attribute to case it to
+ * @return true for success, false for failure.
+ */
+bool radius_cast_tmpl(value_pair_tmpl_t *vpt, DICT_ATTR const *da)
+{
+ VALUE_PAIR *vp;
+ value_data_t *data;
+
+ rad_assert(vpt != NULL);
+ rad_assert(da != NULL);
+ rad_assert(vpt->type == VPT_TYPE_LITERAL);
+
+ vp = pairalloc(vpt, da);
+ if (!vp) return false;
+
+ if (pairparsevalue(vp, vpt->name, 0) < 0) {
+ pairfree(&vp);
+ return false;
+ }
+
+ vpt->vpt_length = vp->length;
+ vpt->vpt_value = data = talloc(vpt, value_data_t);
+ if (!vpt->vpt_value) return false;
+
+ vpt->type = VPT_TYPE_DATA;
+ vpt->vpt_da = da;
+
+ if (vp->da->flags.is_pointer) {
+ data->ptr = talloc_steal(vpt, vp->data.ptr);
+ vp->data.ptr = NULL;
+ } else {
+ memcpy(data, &vp->data, sizeof(*data));
+ }
+
+ pairfree(&vp);
+
+ return true;
+}
/* mutually-recursive static functions need a prototype up front */
static modcallable *do_compile_modgroup(modcallable *,
rlm_components_t, CONF_SECTION *,
- int, int);
+ int, int, int);
/* Actions may be a positive integer (the highest one returned in the group
* will be returned), or the keyword "return", represented here by
GROUPTYPE_COUNT
} grouptype; /* after mc */
modcallable *children;
+ modcallable *tail; /* of the children list */
CONF_SECTION *cs;
value_pair_map_t *map; /* update */
+ value_pair_tmpl_t *vpt; /* switch */
fr_cond_t *cond; /* if/elsif */
+ bool done_pass2;
} modgroup;
typedef struct {
char *xlat_name;
} modxlat;
+/*
static const FR_NAME_NUMBER grouptype_table[] = {
{ "", GROUPTYPE_SIMPLE },
{ "redundant ", GROUPTYPE_REDUNDANT },
{ "append ", GROUPTYPE_APPEND },
{ NULL, -1 }
};
+*/
/* Simple conversions: modsingle and modgroup are subclasses of modcallable,
* so we often want to go back and forth between them. */
}
/* modgroups are grown by adding a modcallable to the end */
-/* FIXME: This is O(N^2) */
static void add_child(modgroup *g, modcallable *c)
{
- modcallable **head = &g->children;
- modcallable *node = *head;
- modcallable **last = head;
-
if (!c) return;
- while (node) {
- last = &node->next;
- node = node->next;
+ if (!g->children) {
+ g->children = g->tail = c;
+ } else {
+ rad_assert(g->tail->next == NULL);
+ g->tail->next = c;
+ g->tail = c;
}
- rad_assert(c->next == NULL);
- *last = c;
c->parent = mod_grouptocallable(g);
}
#define safe_unlock(foo)
#endif
-static int call_modsingle(rlm_components_t component, modsingle *sp, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) call_modsingle(rlm_components_t component, modsingle *sp, REQUEST *request)
{
- int myresult;
int blocked;
- rad_assert(request != NULL);
-
/*
* If the request should stop, refuse to do anything.
*/
blocked = (request->master_state == REQUEST_STOP_PROCESSING);
if (blocked) return RLM_MODULE_NOOP;
- RDEBUG3(" modsingle[%s]: calling %s (%s) for request %d",
+ RINDENT();
+ RDEBUG3("modsingle[%s]: calling %s (%s) for request %d",
comp2str[component], sp->modinst->name,
sp->modinst->entry->name, request->number);
- if (sp->modinst->dead) {
- myresult = RLM_MODULE_FAIL;
+ if (sp->modinst->force) {
+ request->rcode = sp->modinst->code;
goto fail;
}
*/
request->module = sp->modinst->name;
- myresult = sp->modinst->entry->module->methods[component](
- sp->modinst->insthandle, request);
+ request->rcode = sp->modinst->entry->module->methods[component](sp->modinst->insthandle, request);
request->module = "";
safe_unlock(sp->modinst);
}
fail:
- RDEBUG3(" modsingle[%s]: returned from %s (%s) for request %d",
+ REXDENT();
+ RDEBUG3("modsingle[%s]: returned from %s (%s) for request %d",
comp2str[component], sp->modinst->name,
sp->modinst->entry->name, request->number);
- return myresult;
+ return request->rcode;
}
static int default_component_results[RLM_COMPONENT_COUNT] = {
* iteratively, and manage the call stack ourselves.
*/
typedef struct modcall_stack_entry_t {
- int result;
+ rlm_rcode_t result;
int priority;
int unwind; /* unwind to this one if it exists */
modcallable *c;
*/
static void modcall_child(REQUEST *request, rlm_components_t component, int depth,
modcall_stack_entry_t *entry, modcallable *c,
- int *result)
+ rlm_rcode_t *result)
{
modcall_stack_entry_t *next;
{
bool if_taken, was_if;
modcallable *c;
- int result, priority;
+ int priority;
+ rlm_rcode_t result;
was_if = if_taken = false;
result = RLM_MODULE_UNKNOWN;
g = mod_callabletogroup(c);
rad_assert(g->cond != NULL);
- RDEBUG2("%.*s? %s %s", depth + 1, modcall_spaces,
+ RDEBUG2("%.*s %s %s", depth + 1, modcall_spaces,
group_name[c->type], c->name);
condition = radius_evaluate_cond(request, result, 0, g->cond);
condition = false;
REDEBUG("Failed retrieving values required to evaluate condition");
} else {
- RDEBUG2("%.*s? %s %s -> %s", depth + 1, modcall_spaces,
+ RDEBUG2("%.*s %s %s -> %s", depth + 1, modcall_spaces,
group_name[c->type],
c->name, condition ? "TRUE" : "FALSE");
}
MOD_LOG_OPEN_BRACE("update");
for (map = g->map; map != NULL; map = map->next) {
- rcode = radius_map2request(request, map, "update", radius_map2vp, NULL);
+ rcode = radius_map2request(request, map, radius_map2vp, NULL);
if (rcode < 0) {
result = (rcode == -2) ? RLM_MODULE_INVALID : RLM_MODULE_FAIL;
MOD_LOG_CLOSE_BRACE();
*/
if (c->type == MOD_FOREACH) {
int i, foreach_depth = -1;
- VALUE_PAIR *vp;
+ VALUE_PAIR *vps, *vp;
modcall_stack_entry_t *next = NULL;
- vp_cursor_t cursor;
+ vp_cursor_t cursor, copy;
modgroup *g = mod_callabletogroup(c);
if (depth >= MODCALL_STACK_MAX) {
goto calculate_result;
}
- if (radius_get_vp(&vp, request, c->name) < 0) {
- RDEBUG("Unknown Attribute \"%s\"", c->name);
- result = RLM_MODULE_FAIL;
- goto calculate_result;
- }
-
- if (!vp) { /* nothing to loop over */
+ if (radius_tmpl_get_vp(&vp, request, g->vpt) < 0) { /* nothing to loop over */
MOD_LOG_OPEN_BRACE("foreach");
result = RLM_MODULE_NOOP;
MOD_LOG_CLOSE_BRACE();
goto calculate_result;
}
- RDEBUG2("%.*sforeach %s ", depth + 1, modcall_spaces,
- c->name);
+ /*
+ * Copy the VPs from the original request, this ensures deterministic
+ * behaviour if someone decides to add or remove VPs in the set were
+ * iterating over.
+ */
+ vps = NULL;
+
+ fr_cursor_init(&cursor, &vp);
- paircursor(&cursor, &vp);
/* Prime the cursor. */
cursor.found = cursor.current;
- while (vp) {
- VALUE_PAIR *copy = NULL, **copy_p;
+ for (fr_cursor_init(©, &vps);
+ vp;
+ vp = fr_cursor_next_by_da(&cursor, vp->da, g->vpt->attribute.tag)) {
+ VALUE_PAIR *tmp;
+
+ MEM(tmp = paircopyvp(request, vp));
+ fr_cursor_insert(©, tmp);
+ }
+
+ RDEBUG2("%.*sforeach %s ", depth + 1, modcall_spaces, c->name);
+
+ rad_assert(vps != NULL);
+ /*
+ * This is the actual body of the foreach loop
+ */
+ for (vp = fr_cursor_first(©);
+ vp != NULL;
+ vp = fr_cursor_next(©)) {
#ifndef NDEBUG
if (fr_debug_flag >= 2) {
char buffer[1024];
#endif
/*
- * Copy only the one VP we care about.
- */
- copy = paircopyvp(request, vp);
- copy_p = ©
-
- /*
- * @fixme: The old code freed copy on
- * request_data_add or request_data_get.
- * There's no way to easily do that now.
- * The foreach code should be audited for
- * possible memory leaks, though it's not
- * a huge priority as any leaked memory
- * will be freed on request free.
+ * Add the vp to the request, so that
+ * xlat.c, xlat_foreach() can find it.
*/
- request_data_add(request, radius_get_vp, foreach_depth, copy_p, false);
+ request_data_add(request, radius_get_vp, foreach_depth, &vp, false);
/*
* Initialize the childs stack frame.
next->unwind = 0;
if (!modcall_recurse(request, component, depth + 1, next)) {
- request_data_get(request, radius_get_vp, foreach_depth);
- pairfree(©);
- break;
- }
-
- vp = pairfindnext(&cursor, vp->da->attr, vp->da->vendor, TAG_ANY);
-
- /*
- * Delete the cached attribute, if it exists.
- */
- if (copy) {
- request_data_get(request, radius_get_vp, foreach_depth);
- pairfree(©);
- } else {
break;
}
}
} /* loop over VPs */
+ pairfree(&vps);
+
+ rad_assert(next != NULL);
result = next->result;
priority = next->priority;
MOD_LOG_CLOSE_BRACE();
for (i = 8; i >= 0; i--) {
copy_p = request_data_get(request, radius_get_vp, i);
if (copy_p) {
- RDEBUG2("%.*s # break Foreach-Variable-%d", depth + 1,
- modcall_spaces, i);
- pairfree(copy_p);
+ RDEBUG2("%.*s # break Foreach-Variable-%d", depth + 1, modcall_spaces, i);
break;
}
}
goto next_sibling;
}
- MOD_LOG_OPEN_BRACE(cf_section_name1(g->cs));
+ if (c->name) {
+ MOD_LOG_OPEN_BRACE(cf_section_name1(g->cs));
+ } else {
+ RDEBUG2("%.*s%s {", depth + 1, modcall_spaces, cf_section_name1(g->cs));
+ }
modcall_child(request, component,
depth + 1, entry, g->children,
&result);
#ifdef WITH_UNLANG
if (c->type == MOD_SWITCH) {
modcallable *this, *found, *null_case;
- modgroup *g;
- char buffer[1024];
+ modgroup *g, *h;
+ fr_cond_t cond;
+ value_pair_map_t map;
MOD_LOG_OPEN_BRACE("switch");
+ g = mod_callabletogroup(c);
+
+ memset(&cond, 0, sizeof(cond));
+ memset(&map, 0, sizeof(map));
+
+ cond.type = COND_TYPE_MAP;
+ cond.data.map = ↦
+
+ map.op = T_OP_CMP_EQ;
+ map.ci = cf_sectiontoitem(g->cs);
+
+ rad_assert(g->vpt != NULL);
+
+ null_case = found = NULL;
+
/*
- * If there's no %, it refers to an attribute.
- * Otherwise, expand it.
+ * The attribute doesn't exist. We can skip
+ * directly to the default 'case' statement.
*/
- if (!strchr(c->name, '%')) {
- VALUE_PAIR *vp = NULL;
-
- radius_get_vp(&vp, request, c->name);
- if (vp) {
- vp_prints_value(buffer,
- sizeof(buffer),
- vp, 0);
- } else {
- *buffer = '\0';
+ if ((g->vpt->type == VPT_TYPE_ATTR) && (radius_tmpl_get_vp(NULL, request, g->vpt) < 0)) {
+ for (this = g->children; this; this = this->next) {
+ rad_assert(this->type == MOD_CASE);
+
+ h = mod_callabletogroup(this);
+ if (h->vpt) continue;
+
+ found = this;
+ break;
}
- } else {
- radius_xlat(buffer, sizeof(buffer),
- request, c->name, NULL, NULL);
+
+ goto do_null_case;
}
/*
* Find either the exact matching name, or the
* "case {...}" statement.
*/
- g = mod_callabletogroup(c);
- null_case = found = NULL;
for (this = g->children; this; this = this->next) {
- if (!this->name) {
+ rad_assert(this->type == MOD_CASE);
+
+ h = mod_callabletogroup(this);
+
+ /*
+ * Remember the default case
+ */
+ if (!h->vpt) {
if (!null_case) null_case = this;
continue;
}
- if (strcmp(buffer, this->name) == 0) {
+
+ /*
+ * If we're switching over an attribute
+ * AND we haven't pre-parsed the data for
+ * the case statement, then cast the data
+ * to the type of the attribute.
+ */
+ if ((g->vpt->type == VPT_TYPE_ATTR) &&
+ (h->vpt->type != VPT_TYPE_DATA)) {
+ map.src = g->vpt;
+ map.dst = h->vpt;
+ cond.cast = g->vpt->vpt_da;
+
+ /*
+ * Remove unnecessary casting.
+ */
+ if ((h->vpt->type == VPT_TYPE_ATTR) &&
+ (g->vpt->vpt_da->type == h->vpt->vpt_da->type)) {
+ cond.cast = NULL;
+ }
+ } else {
+ map.src = h->vpt;
+ map.dst = g->vpt;
+ cond.cast = NULL;
+ }
+
+ if (radius_evaluate_map(request, RLM_MODULE_UNKNOWN, 0,
+ &cond) == 1) {
found = this;
break;
}
if (!found) found = null_case;
- MOD_LOG_OPEN_BRACE(group_name[c->type]);
+ do_null_case:
modcall_child(request, component,
depth + 1, entry, found,
&result);
{
modcall_stack_entry_t stack[MODCALL_STACK_MAX];
+#ifndef NDEBUG
+ memset(stack, 0, sizeof(stack));
+#endif
/*
* Set up the initial stack frame.
*/
modgroup *g;
modcallable *csingle;
value_pair_map_t *map, *head = NULL;
+ CONF_ITEM *ci;
/*
* This looks at cs->name2 to determine which list to update
return NULL;
}
- for (map = head; map != NULL; map = map->next) {
- if ((map->dst->type == VPT_TYPE_ATTR) && (map->src->type == VPT_TYPE_LITERAL)) {
+ for (map = head, ci = cf_item_find_next(cs, NULL);
+ map != NULL;
+ map = map->next, ci = cf_item_find_next(cs, ci)) {
+ /*
+ * Can't copy an xlat expansion or literal into a list,
+ * we don't know what type of attribute we'd need
+ * to create.
+ *
+ * The only exception is where were using a unary
+ * operator like !*.
+ */
+ if ((map->dst->type == VPT_TYPE_LIST) &&
+ (map->op != T_OP_CMP_FALSE) &&
+ ((map->src->type == VPT_TYPE_XLAT) || (map->src->type == VPT_TYPE_LITERAL))) {
+ cf_log_err(map->ci, "Can't copy value into list (we don't know which attribute to create)");
+ talloc_free(head);
+ return NULL;
+ }
+
+ /*
+ * If LHS is an attribute, and RHS is a literal, we can
+ * preparse the information into a VPT_TYPE_DATA.
+ *
+ * Unless it's a unary operator in which case we
+ * ignore map->src.
+ */
+ if ((map->dst->type == VPT_TYPE_ATTR) && (map->op != T_OP_CMP_FALSE) &&
+ (map->src->type == VPT_TYPE_LITERAL)) {
+ CONF_PAIR *cp;
+
+ cp = cf_itemtopair(ci);
+ rad_assert(cp != NULL);
+
/*
- * If LHS is an attribute, and RHS is a literal, we can
- * check that the format is correct.
+ * It's a literal string, just copy it.
+ * Don't escape anything.
*/
- VALUE_PAIR *vp;
- bool ret;
+ if ((map->dst->vpt_da->type == PW_TYPE_STRING) &&
+ (cf_pair_value_type(cp) == T_SINGLE_QUOTED_STRING)) {
+ value_data_t *vpd;
- MEM(vp = pairalloc(cs, map->dst->da));
- vp->op = map->op;
+ map->src->vpt_value = vpd = talloc_zero(map->src, value_data_t);
+ rad_assert(vpd != NULL);
- ret = pairparsevalue(vp, map->src->name);
- talloc_free(vp);
- if (!ret) {
- talloc_free(head);
- cf_log_err(map->ci, "%s", fr_strerror());
- return NULL;
+ vpd->strvalue = talloc_typed_strdup(vpd, map->src->name);
+ rad_assert(vpd->strvalue != NULL);
+
+ map->src->type = VPT_TYPE_DATA;
+ map->src->vpt_da = map->dst->vpt_da;
+ map->src->vpt_length = talloc_array_length(vpd->strvalue) - 1;
+ } else {
+ if (!radius_cast_tmpl(map->src, map->dst->vpt_da)) {
+ cf_log_err(map->ci, "%s", fr_strerror());
+ talloc_free(head);
+ return NULL;
+ }
}
- }
- }
+ } /* else we can't precompile the data */
+ } /* loop over the conf_pairs in the update section */
g = rad_malloc(sizeof(*g)); /* never fails */
memset(g, 0, sizeof(*g));
}
-static modcallable *do_compile_modswitch(modcallable *parent, UNUSED rlm_components_t component, CONF_SECTION *cs)
+static modcallable *do_compile_modswitch(modcallable *parent, rlm_components_t component, CONF_SECTION *cs)
{
- modcallable *csingle;
CONF_ITEM *ci;
- int had_seen_default = false;
+ FR_TOKEN type;
+ char const *name2;
+ bool had_seen_default = false;
+ modcallable *csingle;
+ modgroup *g;
+ value_pair_tmpl_t *vpt;
- if (!cf_section_name2(cs)) {
+ name2 = cf_section_name2(cs);
+ if (!name2) {
cf_log_err_cs(cs,
- "You must specify a variable to switch over for 'switch'.");
+ "You must specify a variable to switch over for 'switch'");
return NULL;
}
if (!cf_item_find_next(cs, NULL)) {
- cf_log_err_cs(cs, "'switch' statements cannot be empty.");
+ cf_log_err_cs(cs, "'switch' statements cannot be empty");
+ return NULL;
+ }
+
+ /*
+ * Create the template. If we fail, AND it's a bare word
+ * with &Foo-Bar, it MAY be an attribute defined by a
+ * module. Allow it for now. The pass2 checks below
+ * will fix it up.
+ */
+ type = cf_section_name2_type(cs);
+ vpt = radius_str2tmpl(cs, name2, type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
+ if (!vpt && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
+ cf_log_err_cs(cs, "Syntax error in '%s': %s", name2, fr_strerror());
return NULL;
}
/*
+ * Otherwise a NULL vpt may refer to an attribute defined
+ * by a module. That is checked in pass 2.
+ */
+
+ /*
* Walk through the children of the switch section,
* ensuring that they're all 'case' statements
*/
ci != NULL;
ci=cf_item_find_next(cs, ci)) {
CONF_SECTION *subcs;
- char const *name1, *name2;
+ char const *name1;
if (!cf_item_is_section(ci)) {
if (!cf_item_is_pair(ci)) continue;
cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
+ talloc_free(vpt);
return NULL;
}
if (strcmp(name1, "case") != 0) {
cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
+ talloc_free(vpt);
return NULL;
}
if (!name2 || (name2[0] == '\0')) {
cf_log_err(ci, "\"case\" sections must have a name");
+ talloc_free(vpt);
+ return NULL;
+ }
+ }
+
+ csingle = do_compile_modgroup(parent, component, cs,
+ GROUPTYPE_SIMPLE,
+ GROUPTYPE_SIMPLE,
+ MOD_SWITCH);
+ if (!csingle) {
+ talloc_free(vpt);
+ return NULL;
+ }
+
+ g = mod_callabletogroup(csingle);
+ g->vpt = vpt;
+
+ return csingle;
+}
+
+static modcallable *do_compile_modcase(modcallable *parent, rlm_components_t component, CONF_SECTION *cs)
+{
+ int i;
+ char const *name2;
+ modcallable *csingle;
+ modgroup *g;
+ value_pair_tmpl_t *vpt;
+
+ if (!parent || (parent->type != MOD_SWITCH)) {
+ cf_log_err_cs(cs, "\"case\" statements may only appear within a \"switch\" section");
+ return NULL;
+ }
+
+ /*
+ * case THING means "match THING"
+ * case means "match anything"
+ */
+ name2 = cf_section_name2(cs);
+ if (name2) {
+ FR_TOKEN type;
+
+ type = cf_section_name2_type(cs);
+
+ vpt = radius_str2tmpl(cs, name2, type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
+ if (!vpt && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
+ cf_log_err_cs(cs, "Syntax error in '%s': %s", name2, fr_strerror());
return NULL;
}
+
+ /*
+ * Otherwise a NULL vpt may refer to an attribute defined
+ * by a module. That is checked in pass 2.
+ */
+
+ } else {
+ vpt = NULL;
+ }
+
+ csingle= do_compile_modgroup(parent, component, cs,
+ GROUPTYPE_SIMPLE,
+ GROUPTYPE_SIMPLE,
+ MOD_CASE);
+ if (!csingle) {
+ talloc_free(vpt);
+ return NULL;
+ }
+
+ /*
+ * The interpretor expects this to be NULL for the
+ * default case. do_compile_modgroup sets it to name2,
+ * unless name2 is NULL, in which case it sets it to name1.
+ */
+ csingle->name = name2;
+
+ g = mod_callabletogroup(csingle);
+ g->vpt = vpt;
+
+ /*
+ * Set all of it's codes to return, so that
+ * when we pick a 'case' statement, we don't
+ * fall through to processing the next one.
+ */
+ for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
+ csingle->actions[i] = MOD_ACTION_RETURN;
}
- csingle = do_compile_modgroup(parent, component, cs, GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE);
- if (!csingle) return NULL;
- csingle->type = MOD_SWITCH;
return csingle;
}
static modcallable *do_compile_modforeach(modcallable *parent,
- UNUSED rlm_components_t component, CONF_SECTION *cs,
- char const *name2)
+ UNUSED rlm_components_t component, CONF_SECTION *cs)
{
+ FR_TOKEN type;
+ char const *name2;
modcallable *csingle;
+ modgroup *g;
+ value_pair_tmpl_t *vpt;
- if (!cf_section_name2(cs)) {
+ name2 = cf_section_name2(cs);
+ if (!name2) {
cf_log_err_cs(cs,
- "You must specify an attribute to loop over in 'foreach'.");
+ "You must specify an attribute to loop over in 'foreach'");
return NULL;
}
if (!cf_item_find_next(cs, NULL)) {
- cf_log_err_cs(cs, "'foreach' blocks cannot be empty.");
+ cf_log_err_cs(cs, "'foreach' blocks cannot be empty");
return NULL;
}
- csingle= do_compile_modgroup(parent, component, cs,
- GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE);
- if (!csingle) return NULL;
- csingle->name = name2;
- csingle->type = MOD_FOREACH;
+ /*
+ * Create the template. If we fail, AND it's a bare word
+ * with &Foo-Bar, it MAY be an attribute defined by a
+ * module. Allow it for now. The pass2 checks below
+ * will fix it up.
+ */
+ type = cf_section_name2_type(cs);
+ vpt = radius_str2tmpl(cs, name2, type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
+ if (!vpt && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
+ cf_log_err_cs(cs, "Syntax error in '%s': %s", name2, fr_strerror());
+ return NULL;
+ }
+
+ if (vpt && (vpt->type != VPT_TYPE_ATTR)) {
+ cf_log_err_cs(cs, "MUST use attribute reference in 'foreach'");
+ return NULL;
+ }
+
+ csingle = do_compile_modgroup(parent, component, cs,
+ GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
+ MOD_FOREACH);
+
+ if (!csingle) {
+ talloc_free(vpt);
+ return NULL;
+ }
+
+ g = mod_callabletogroup(csingle);
+ g->vpt = vpt;
+
return csingle;
}
static modcallable *do_compile_modbreak(modcallable *parent,
rlm_components_t component, CONF_ITEM const *ci)
{
- modcallable *csingle;
CONF_SECTION const *cs = NULL;
for (cs = cf_item_parent(ci);
return NULL;
}
- csingle = do_compile_modgroup(parent, component, NULL,
- GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE);
- if (!csingle) return NULL;
- csingle->name = "";
- csingle->type = MOD_BREAK;
- return csingle;
+ return do_compile_modgroup(parent, component, NULL,
+ GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
+ MOD_BREAK);
}
#endif
modcallable *csingle;
module_instance_t *this;
CONF_SECTION *cs, *subcs, *modules;
+ char const *realname;
if (cf_item_is_section(ci)) {
char const *name2;
*modname = name2;
return do_compile_modgroup(parent, component, cs,
GROUPTYPE_SIMPLE,
- grouptype);
+ grouptype, MOD_GROUP);
} else if (strcmp(modrefname, "redundant") == 0) {
*modname = name2;
return do_compile_modgroup(parent, component, cs,
GROUPTYPE_REDUNDANT,
- grouptype);
+ grouptype, MOD_GROUP);
} else if (strcmp(modrefname, "append") == 0) {
*modname = name2;
return do_compile_modgroup(parent, component, cs,
GROUPTYPE_APPEND,
- grouptype);
+ grouptype, MOD_GROUP);
} else if (strcmp(modrefname, "load-balance") == 0) {
*modname = name2;
return NULL;
}
- csingle= do_compile_modgroup(parent, component, cs,
- GROUPTYPE_SIMPLE,
- grouptype);
- if (!csingle) return NULL;
- csingle->type = MOD_LOAD_BALANCE;
- return csingle;
+ return do_compile_modgroup(parent, component, cs,
+ GROUPTYPE_SIMPLE,
+ grouptype, MOD_LOAD_BALANCE);
} else if (strcmp(modrefname, "redundant-load-balance") == 0) {
*modname = name2;
return NULL;
}
- csingle= do_compile_modgroup(parent, component, cs,
- GROUPTYPE_REDUNDANT,
- grouptype);
- if (!csingle) return NULL;
- csingle->type = MOD_REDUNDANT_LOAD_BALANCE;
- return csingle;
+ return do_compile_modgroup(parent, component, cs,
+ GROUPTYPE_REDUNDANT,
+ grouptype, MOD_REDUNDANT_LOAD_BALANCE);
#ifdef WITH_UNLANG
} else if (strcmp(modrefname, "if") == 0) {
- modgroup *g;
-
if (!cf_section_name2(cs)) {
- cf_log_err(ci, "'if' without condition.");
+ cf_log_err(ci, "'if' without condition");
return NULL;
}
*modname = name2;
csingle= do_compile_modgroup(parent, component, cs,
GROUPTYPE_SIMPLE,
- grouptype);
+ grouptype, MOD_IF);
if (!csingle) return NULL;
- csingle->type = MOD_IF;
*modname = name2;
- g = mod_callabletogroup(csingle);
- g->cond = cf_data_find(g->cs, "if");
- rad_assert(g->cond != NULL);
-
return csingle;
} else if (strcmp(modrefname, "elsif") == 0) {
- modgroup *g;
-
if (parent &&
((parent->type == MOD_LOAD_BALANCE) ||
(parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
- cf_log_err(ci, "'elsif' cannot be used in this section.");
+ cf_log_err(ci, "'elsif' cannot be used in this section");
return NULL;
}
if (!cf_section_name2(cs)) {
- cf_log_err(ci, "'elsif' without condition.");
+ cf_log_err(ci, "'elsif' without condition");
return NULL;
}
*modname = name2;
- csingle= do_compile_modgroup(parent, component, cs,
- GROUPTYPE_SIMPLE,
- grouptype);
- if (!csingle) return NULL;
- csingle->type = MOD_ELSIF;
- *modname = name2;
-
- g = mod_callabletogroup(csingle);
- g->cond = cf_data_find(g->cs, "if");
- rad_assert(g->cond != NULL);
-
- return csingle;
+ return do_compile_modgroup(parent, component, cs,
+ GROUPTYPE_SIMPLE,
+ grouptype, MOD_ELSIF);
} else if (strcmp(modrefname, "else") == 0) {
if (parent &&
((parent->type == MOD_LOAD_BALANCE) ||
(parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
- cf_log_err(ci, "'else' cannot be used in this section section.");
+ cf_log_err(ci, "'else' cannot be used in this section section");
return NULL;
}
if (cf_section_name2(cs)) {
- cf_log_err(ci, "Cannot have conditions on 'else'.");
+ cf_log_err(ci, "Cannot have conditions on 'else'");
return NULL;
}
*modname = name2;
- csingle= do_compile_modgroup(parent, component, cs,
- GROUPTYPE_SIMPLE,
- grouptype);
- if (!csingle) return NULL;
- csingle->type = MOD_ELSE;
- return csingle;
+ return do_compile_modgroup(parent, component, cs,
+ GROUPTYPE_SIMPLE,
+ grouptype, MOD_ELSE);
} else if (strcmp(modrefname, "update") == 0) {
*modname = name2;
- csingle = do_compile_modupdate(parent, component, cs,
- name2);
- if (!csingle) return NULL;
-
- return csingle;
+ return do_compile_modupdate(parent, component, cs,
+ name2);
} else if (strcmp(modrefname, "switch") == 0) {
*modname = name2;
- csingle = do_compile_modswitch(parent, component, cs);
- if (!csingle) return NULL;
-
- return csingle;
+ return do_compile_modswitch(parent, component, cs);
} else if (strcmp(modrefname, "case") == 0) {
- int i;
-
*modname = name2;
- if (!parent) {
- cf_log_err(ci, "\"case\" statements may only appear within a \"switch\" section");
- return NULL;
- }
-
- csingle= do_compile_modgroup(parent, component, cs,
- GROUPTYPE_SIMPLE,
- grouptype);
- if (!csingle) return NULL;
- csingle->type = MOD_CASE;
- csingle->name = cf_section_name2(cs); /* may be NULL */
-
- /*
- * Set all of it's codes to return, so that
- * when we pick a 'case' statement, we don't
- * fall through to processing the next one.
- */
- for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
- csingle->actions[i] = MOD_ACTION_RETURN;
- }
-
- return csingle;
+ return do_compile_modcase(parent, component, cs);
} else if (strcmp(modrefname, "foreach") == 0) {
*modname = name2;
- csingle = do_compile_modforeach(parent, component, cs,
- name2);
- if (!csingle) return NULL;
+ return do_compile_modforeach(parent, component, cs);
- return csingle;
#endif
} /* else it's something like sql { fail = 1 ...} */
}
if (subcs) {
- cf_log_module(cs, "Loading virtual module %s",
- modrefname);
-
/*
* redundant foo {} is a single.
*/
component,
subcs,
GROUPTYPE_SIMPLE,
- grouptype);
+ grouptype, MOD_GROUP);
}
}
}
*/
modules = cf_section_find("modules");
this = NULL;
+ realname = modrefname;
if (modules) {
/*
* Try to load the optional module.
*/
- char const *realname = modrefname;
if (realname[0] == '-') realname++;
/*
sizeof csingle->actions);
}
rad_assert(modrefname != NULL);
- csingle->name = modrefname;
+ csingle->name = realname;
csingle->type = MOD_SINGLE;
csingle->method = component;
return csingle;
}
-modcallable *compile_modsingle(modcallable *parent,
+modcallable *compile_modsingle(modcallable **parent,
rlm_components_t component, CONF_ITEM *ci,
char const **modname)
{
- modcallable *ret = do_compile_modsingle(parent, component, ci,
- GROUPTYPE_SIMPLE,
- modname);
+ modcallable *ret;
+
+ if (!*parent) {
+ modcallable *c;
+ modgroup *g;
+ CONF_SECTION *parentcs;
+
+ g = rad_malloc(sizeof *g);
+ memset(g, 0, sizeof(*g));
+ g->grouptype = GROUPTYPE_SIMPLE;
+ c = mod_grouptocallable(g);
+ c->next = NULL;
+ memcpy(c->actions,
+ defaultactions[component][GROUPTYPE_SIMPLE],
+ sizeof(c->actions));
+
+ parentcs = cf_item_parent(ci);
+ c->name = cf_section_name2(parentcs);
+ if (!c->name) {
+ c->name = cf_section_name1(parentcs);
+ }
+
+ c->type = MOD_GROUP;
+ c->method = component;
+ g->children = NULL;
+
+ *parent = mod_grouptocallable(g);
+ }
+
+ ret = do_compile_modsingle(*parent, component, ci,
+ GROUPTYPE_SIMPLE,
+ modname);
dump_tree(component, ret);
return ret;
}
*/
static modcallable *do_compile_modgroup(modcallable *parent,
rlm_components_t component, CONF_SECTION *cs,
- int grouptype, int parentgrouptype)
+ int grouptype, int parentgrouptype, int mod_type)
{
int i;
modgroup *g;
c = mod_grouptocallable(g);
c->parent = parent;
- c->type = MOD_GROUP;
+ c->type = mod_type;
c->next = NULL;
memset(c->actions, 0, sizeof(c->actions));
c->name = cf_section_name1(cs);
if (strcmp(c->name, "group") == 0) {
c->name = "";
- } else {
+ } else if (c->type == MOD_GROUP) {
c->type = MOD_POLICY;
}
}
+#ifdef WITH_UNLANG
/*
- * Loop over the children of this group.
+ * Do load-time optimizations
*/
- for (ci=cf_item_find_next(cs, NULL);
- ci != NULL;
- ci=cf_item_find_next(cs, ci)) {
+ if ((c->type == MOD_IF) || (c->type == MOD_ELSIF) || (c->type == MOD_ELSE)) {
+ modgroup *f, *p;
- /*
- * Sections are references to other groups, or
- * to modules with updated return codes.
- */
- if (cf_item_is_section(ci)) {
- char const *junk = NULL;
- modcallable *single;
- CONF_SECTION *subcs = cf_itemtosection(ci);
+ rad_assert(parent != NULL);
- single = do_compile_modsingle(c, component, ci,
- grouptype, &junk);
- if (!single) {
- cf_log_err(ci, "Failed to parse \"%s\" subsection.",
- cf_section_name1(subcs));
- modcallable_free(&c);
- return NULL;
+ if (c->type == MOD_IF) {
+ g->cond = cf_data_find(g->cs, "if");
+ rad_assert(g->cond != NULL);
+
+ check_if:
+ if (g->cond->type == COND_TYPE_FALSE) {
+ INFO(" # Skipping contents of '%s' as it is always 'false' -- %s:%d",
+ group_name[g->mc.type],
+ cf_section_filename(g->cs), cf_section_lineno(g->cs));
+ goto set_codes;
}
- add_child(g, single);
+
+ } else if (c->type == MOD_ELSIF) {
+
+ g->cond = cf_data_find(g->cs, "if");
+ rad_assert(g->cond != NULL);
+
+ rad_assert(parent != NULL);
+ p = mod_callabletogroup(parent);
+
+ rad_assert(p->tail != NULL);
+
+ f = mod_callabletogroup(p->tail);
+ rad_assert((f->mc.type == MOD_IF) ||
+ (f->mc.type == MOD_ELSIF));
+
+ /*
+ * If we took the previous condition, we
+ * don't need to take this one.
+ *
+ * We reset our condition to 'true', so
+ * that subsequent sections can check
+ * that they don't need to be executed.
+ */
+ if (f->cond->type == COND_TYPE_TRUE) {
+ skip_true:
+ INFO(" # Skipping contents of '%s' as previous '%s' is always 'true' -- %s:%d",
+ group_name[g->mc.type],
+ group_name[f->mc.type],
+ cf_section_filename(g->cs), cf_section_lineno(g->cs));
+ g->cond = f->cond;
+ goto set_codes;
+ }
+ goto check_if;
+
+ } else {
+ rad_assert(c->type == MOD_ELSE);
+
+ rad_assert(parent != NULL);
+ p = mod_callabletogroup(parent);
+
+ rad_assert(p->tail != NULL);
+
+ f = mod_callabletogroup(p->tail);
+ rad_assert((f->mc.type == MOD_IF) ||
+ (f->mc.type == MOD_ELSIF));
+
+ /*
+ * If we took the previous condition, we
+ * don't need to take this one.
+ */
+ if (f->cond->type == COND_TYPE_TRUE) goto skip_true;
+ }
+
+ /*
+ * Else we need to compile this section
+ */
+ }
+#endif
+
+ /*
+ * Loop over the children of this group.
+ */
+ for (ci=cf_item_find_next(cs, NULL);
+ ci != NULL;
+ ci=cf_item_find_next(cs, ci)) {
+
+ /*
+ * Sections are references to other groups, or
+ * to modules with updated return codes.
+ */
+ if (cf_item_is_section(ci)) {
+ char const *junk = NULL;
+ modcallable *single;
+ CONF_SECTION *subcs = cf_itemtosection(ci);
+
+ single = do_compile_modsingle(c, component, ci,
+ grouptype, &junk);
+ if (!single) {
+ cf_log_err(ci, "Failed to parse \"%s\" subsection.",
+ cf_section_name1(subcs));
+ modcallable_free(&c);
+ return NULL;
+ }
+ add_child(g, single);
} else if (!cf_item_is_pair(ci)) { /* CONF_DATA */
continue;
{
modcallable *ret = do_compile_modgroup(parent, component, cs,
GROUPTYPE_SIMPLE,
- GROUPTYPE_SIMPLE);
- dump_tree(component, ret);
+ GROUPTYPE_SIMPLE, MOD_GROUP);
+
+ if (debug_flag > 3) {
+ modcall_debug(ret, 2);
+ }
+
return ret;
}
-void add_to_modcallable(modcallable **parent, modcallable *this,
- rlm_components_t component, char const *name)
+void add_to_modcallable(modcallable *parent, modcallable *this)
{
modgroup *g;
rad_assert(this != NULL);
+ rad_assert(parent != NULL);
- if (*parent == NULL) {
- modcallable *c;
-
- g = rad_malloc(sizeof *g);
- memset(g, 0, sizeof(*g));
- g->grouptype = GROUPTYPE_SIMPLE;
- c = mod_grouptocallable(g);
- c->next = NULL;
- memcpy(c->actions,
- defaultactions[component][GROUPTYPE_SIMPLE],
- sizeof(c->actions));
- rad_assert(name != NULL);
- c->name = name;
- c->type = MOD_GROUP;
- c->method = component;
- g->children = NULL;
-
- *parent = mod_grouptocallable(g);
- } else {
- g = mod_callabletogroup(*parent);
- }
+ g = mod_callabletogroup(parent);
add_child(g, this);
}
#ifdef WITH_UNLANG
+static char const spaces[] = " ";
+
+static bool pass2_xlat_compile(CONF_ITEM const *ci, value_pair_tmpl_t **pvpt, bool convert)
+{
+ ssize_t slen;
+ char *fmt;
+ char const *error;
+ xlat_exp_t *head;
+ value_pair_tmpl_t *vpt;
+
+ vpt = *pvpt;
+
+ rad_assert(vpt->type == VPT_TYPE_XLAT);
+
+ fmt = talloc_typed_strdup(vpt, vpt->name);
+ slen = xlat_tokenize(vpt, fmt, &head, &error);
+
+ if (slen < 0) {
+ char const *prefix = "";
+ char const *p = vpt->name;
+ size_t indent = -slen;
+
+ if (indent >= sizeof(spaces)) {
+ size_t offset = (indent - (sizeof(spaces) - 1)) + (sizeof(spaces) * 0.75);
+ indent -= offset;
+ p += offset;
+
+ prefix = "...";
+ }
+
+ cf_log_err(ci, "Failed parsing expanded string:");
+ cf_log_err(ci, "%s%s", prefix, p);
+ cf_log_err(ci, "%s%.*s^ %s", prefix, (int) indent, spaces, error);
+
+ return false;
+ }
+
+ /*
+ * Convert %{Attribute-Name} to &Attribute-Name
+ */
+ if (convert) {
+ value_pair_tmpl_t *attr;
+
+ attr = radius_xlat2tmpl(talloc_parent(vpt), head);
+ if (attr) {
+ if (cf_item_is_pair(ci)) {
+ CONF_PAIR *cp = cf_itemtopair(ci);
+
+ WARN("%s[%d] Please change %%{%s} to &%s",
+ cf_pair_filename(cp), cf_pair_lineno(cp),
+ attr->name, attr->name);
+ } else {
+ CONF_SECTION *cs = cf_itemtosection(ci);
+
+ WARN("%s[%d] Please change %%{%s} to &%s",
+ cf_section_filename(cs), cf_section_lineno(cs),
+ attr->name, attr->name);
+ }
+ TALLOC_FREE(*pvpt);
+ *pvpt = attr;
+ return true;
+ }
+ }
+
+ /*
+ * Re-write it to be a pre-parsed XLAT structure.
+ */
+ vpt->type = VPT_TYPE_XLAT_STRUCT;
+ vpt->vpt_xlat = head;
+
+ return true;
+}
+
+
+#ifdef HAVE_REGEX_H
+static int _free_compiled_regex(regex_t *preg)
+{
+ regfree(preg);
+ return 0;
+}
+
+static bool pass2_regex_compile(CONF_ITEM const *ci, value_pair_tmpl_t *vpt)
+{
+ int rcode;
+ regex_t *preg;
+
+ rad_assert(vpt->type == VPT_TYPE_REGEX);
+
+ /*
+ * Expanded at run-time. We can't precompile it.
+ */
+ if (strchr(vpt->name, '%')) return true;
+
+ preg = talloc_zero(vpt, regex_t);
+ talloc_set_destructor(preg, _free_compiled_regex);
+ if (!preg) return false;
+
+ rcode = regcomp(preg, vpt->name, REG_EXTENDED | (vpt->vpt_iflag ? REG_ICASE : 0));
+ if (rcode != 0) {
+ char buffer[256];
+ regerror(rcode, preg, buffer, sizeof(buffer));
+
+ cf_log_err(ci, "Invalid regular expression %s: %s",
+ vpt->name, buffer);
+ return false;
+ }
+
+ vpt->type = VPT_TYPE_REGEX_STRUCT;
+ vpt->vpt_preg = preg;
+
+ return true;
+}
+#endif
+
static bool pass2_callback(UNUSED void *ctx, fr_cond_t *c)
{
value_pair_map_t *map;
+ if (c->type == COND_TYPE_EXISTS) {
+ if (c->data.vpt->type == VPT_TYPE_XLAT) {
+ return pass2_xlat_compile(c->ci, &c->data.vpt, true);
+ }
+
+ rad_assert(c->data.vpt->type != VPT_TYPE_REGEX);
+
+ /*
+ * FIXME: fix up attribute references, too!
+ */
+ return true;
+ }
+
/*
* Maps have a paircompare fixup applied to them.
* Others get ignored.
map = c->data.map;
goto check_paircmp;
}
+
return true;
}
* Where "foo" is dynamically defined.
*/
if (c->pass2_fixup == PASS2_FIXUP_TYPE) {
- if (!dict_valbyname(map->dst->da->attr,
- map->dst->da->vendor,
+ if (!dict_valbyname(map->dst->vpt_da->attr,
+ map->dst->vpt_da->vendor,
map->src->name)) {
cf_log_err(map->ci, "Invalid reference to non-existent %s %s { ... }",
- map->dst->da->name,
+ map->dst->vpt_da->name,
map->src->name);
return false;
}
value_pair_map_t *old;
value_pair_tmpl_t vpt;
+ old = c->data.map;
+
/*
* It's still not an attribute. Ignore it.
*/
- if (radius_parse_attr(map->dst->name, &vpt, REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
+ if (radius_parse_attr(&vpt, map->dst->name, REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
+ cf_log_err(old->ci, "Failed parsing condition: %s", fr_strerror());
c->pass2_fixup = PASS2_FIXUP_NONE;
return true;
}
/*
* Re-parse the LHS as an attribute.
*/
- old = c->data.map;
map = radius_str2map(c, old->dst->name, T_BARE_WORD, old->op,
old->src->name, T_BARE_WORD,
REQUEST_CURRENT, PAIR_LIST_REQUEST,
REQUEST_CURRENT, PAIR_LIST_REQUEST);
if (!map) {
- cf_log_err(map->ci, "Failed parsing condition");
+ cf_log_err(old->ci, "Failed parsing condition");
return false;
}
map->ci = old->ci;
/*
* Just in case someone adds a new fixup later.
*/
- rad_assert(c->pass2_fixup == PASS2_FIXUP_NONE);
+ rad_assert((c->pass2_fixup == PASS2_FIXUP_NONE) ||
+ (c->pass2_fixup == PASS2_PAIRCOMPARE));
+
+ /*
+ * Precompile xlat's
+ */
+ if (map->dst->type == VPT_TYPE_XLAT) {
+ /*
+ * Don't compile the LHS to an attribute
+ * reference for now. When we do that, we've got
+ * to check the RHS for type-specific data, and
+ * parse it to a VPT_TYPE_DATA.
+ */
+ if (!pass2_xlat_compile(map->ci, &map->dst, false)) {
+ return false;
+ }
+ }
+
+ if (map->src->type == VPT_TYPE_XLAT) {
+ /*
+ * Convert the RHS to an attribute reference only
+ * if the LHS is an attribute reference, too.
+ *
+ * We can fix this when the code in evaluate.c
+ * can handle strings on the LHS, and attributes
+ * on the RHS. For now, the code in parser.c
+ * forbids this.
+ */
+ if (!pass2_xlat_compile(map->ci, &map->src, (map->dst->type == VPT_TYPE_ATTR))) {
+ return false;
+ }
+ }
+
+ /*
+ * Convert bare refs to %{Foreach-Variable-N}
+ */
+ if ((map->dst->type == VPT_TYPE_LITERAL) &&
+ (strncmp(map->dst->name, "Foreach-Variable-", 17) == 0)) {
+ char *fmt;
+ value_pair_tmpl_t *vpt;
+
+ fmt = talloc_asprintf(map->dst, "%%{%s}", map->dst->name);
+ vpt = radius_str2tmpl(map, fmt, T_DOUBLE_QUOTED_STRING, REQUEST_CURRENT, PAIR_LIST_REQUEST);
+ if (!vpt) {
+ cf_log_err(map->ci, "Failed compiling %s", map->dst->name);
+ talloc_free(fmt);
+ return false;
+ }
+ talloc_free(map->dst);
+ map->dst = vpt;
+ }
+
+#ifdef HAVE_REGEX_H
+ if (map->src->type == VPT_TYPE_REGEX) {
+ if (!pass2_regex_compile(map->ci, map->src)) {
+ return false;
+ }
+ }
+ rad_assert(map->dst->type != VPT_TYPE_REGEX);
+#endif
/*
* Only attributes can have a paircompare registered, and
* with the request pairs.
*/
if ((map->dst->type != VPT_TYPE_ATTR) ||
- (map->dst->request != REQUEST_CURRENT) ||
- (map->dst->list != PAIR_LIST_REQUEST)) {
+ (map->dst->vpt_request != REQUEST_CURRENT) ||
+ (map->dst->vpt_list != PAIR_LIST_REQUEST)) {
return true;
}
- if (!radius_find_compare(map->dst->da)) return true;
+ if (!radius_find_compare(map->dst->vpt_da)) return true;
if (map->src->type == VPT_TYPE_ATTR) {
cf_log_err(map->ci, "Cannot compare virtual attribute %s to another attribute",
return true;
}
+
+
+/*
+ * Compile the RHS of update sections to xlat_exp_t
+ */
+static bool modcall_pass2_update(modgroup *g)
+{
+ value_pair_map_t *map;
+
+ for (map = g->map; map != NULL; map = map->next) {
+ if (map->src->type == VPT_TYPE_XLAT) {
+ rad_assert(map->src->vpt_xlat == NULL);
+
+ /*
+ * FIXME: compile to attribute && handle
+ * the conversion in radius_map2vp().
+ */
+ if (!pass2_xlat_compile(map->ci, &map->src, false)) {
+ return false;
+ }
+ }
+
+ rad_assert(map->src->type != VPT_TYPE_REGEX);
+ }
+
+ return true;
+}
#endif
/*
rad_assert(0 == 1);
break;
- case MOD_SINGLE:
#ifdef WITH_UNLANG
- case MOD_UPDATE: /* @todo: pre-parse xlat's */
+ case MOD_UPDATE:
+ g = mod_callabletogroup(this);
+ if (g->done_pass2) return true;
+
+ if (!modcall_pass2_update(g)) {
+ return false;
+ }
+ g->done_pass2 = true;
+ break;
+
case MOD_XLAT: /* @todo: pre-parse xlat's */
case MOD_BREAK:
case MOD_REFERENCE:
#endif
+
+ case MOD_SINGLE:
break; /* do nothing */
#ifdef WITH_UNLANG
case MOD_IF:
case MOD_ELSIF:
g = mod_callabletogroup(this);
+ if (g->done_pass2) return true;
+
+ /*
+ * Don't walk over these.
+ */
+ if ((g->cond->type == COND_TYPE_TRUE) ||
+ (g->cond->type == COND_TYPE_FALSE)) {
+ break;
+ }
+
+ /*
+ * The compilation code takes care of
+ * simplifying 'true' and 'false'
+ * conditions. For others, we have to do
+ * a second pass to parse && compile xlats.
+ */
if (!fr_condition_walk(g->cond, pass2_callback, NULL)) {
return false;
}
+
+ if (!modcall_pass2(g->children)) return false;
+ g->done_pass2 = true;
+ break;
+#endif
+
+#ifdef WITH_UNLANG
+ case MOD_SWITCH:
+ g = mod_callabletogroup(this);
+ if (g->done_pass2) return true;
+
+ /*
+ * We had &Foo-Bar, where Foo-Bar is
+ * defined by a module.
+ */
+ if (!g->vpt) {
+ rad_assert(this->name != NULL);
+ rad_assert(this->name[0] == '&');
+ rad_assert(cf_section_name2_type(g->cs) == T_BARE_WORD);
+ goto do_case;
+ }
+
+ /*
+ * Statically compile xlats
+ */
+ if (g->vpt->type == VPT_TYPE_XLAT) goto do_case_xlat;
+
+ /*
+ * We may have: switch Foo-Bar {
+ *
+ * where Foo-Bar is an attribute defined
+ * by a module. Since there's no leading
+ * &, it's parsed as a literal. But if
+ * we can parse it as an attribute,
+ * switch to using that.
+ */
+ if (g->vpt->type == VPT_TYPE_LITERAL) {
+ value_pair_tmpl_t *vpt;
+
+ vpt = radius_str2tmpl(g->cs, this->name,
+ cf_section_name2_type(g->cs),
+ REQUEST_CURRENT, PAIR_LIST_REQUEST);
+ if (vpt->type == VPT_TYPE_ATTR) {
+ talloc_free(g->vpt);
+ g->vpt = vpt;
+ }
+ }
+
+ /*
+ * Warn about old-style configuration.
+ *
+ * DEPRECATED: switch User-Name { ...
+ * ALLOWED : switch &User-Name { ...
+ */
+ if ((g->vpt->type == VPT_TYPE_ATTR) &&
+ (this->name[0] != '&')) {
+ WARN("%s[%d]: Please change %s to &%s",
+ cf_section_filename(g->cs),
+ cf_section_lineno(g->cs),
+ this->name, this->name);
+ }
+
+ if (!modcall_pass2(g->children)) return false;
+ g->done_pass2 = true;
+ break;
+
+ case MOD_CASE:
+ g = mod_callabletogroup(this);
+ if (g->done_pass2) return true;
+
+ do_case:
+ /*
+ * The statement may refer to an
+ * attribute which doesn't exist until
+ * all of the modules have been loaded.
+ * Check for that now.
+ */
+ if (!g->vpt && this->name &&
+ (this->name[0] == '&') &&
+ (cf_section_name2_type(g->cs) == T_BARE_WORD)) {
+ g->vpt = radius_str2tmpl(g->cs, this->name,
+ cf_section_name2_type(g->cs),
+ REQUEST_CURRENT, PAIR_LIST_REQUEST);
+ if (!g->vpt) {
+ cf_log_err_cs(g->cs, "Syntax error in '%s': %s",
+ this->name, fr_strerror());
+ return false;
+ }
+ }
+
+ /*
+ * Do type-specific checks on the case statement
+ */
+ if (g->vpt && (g->vpt->type == VPT_TYPE_LITERAL)) {
+ modgroup *f;
+
+ rad_assert(this->parent != NULL);
+ rad_assert(this->parent->type == MOD_SWITCH);
+
+ f = mod_callabletogroup(mc->parent);
+ rad_assert(f->vpt != NULL);
+
+ /*
+ * We're switching over an
+ * attribute. Check that the
+ * values match.
+ */
+ if (f->vpt->type == VPT_TYPE_ATTR) {
+ rad_assert(f->vpt->vpt_da != NULL);
+
+ if (!radius_cast_tmpl(g->vpt, f->vpt->vpt_da)) {
+ cf_log_err_cs(g->cs, "Invalid argument for case statement: %s",
+ fr_strerror());
+ return false;
+ }
+ }
+ }
+
+ do_case_xlat:
+ /*
+ * Compile and sanity check xlat
+ * expansions.
+ */
+ if (g->vpt &&
+ (g->vpt->type == VPT_TYPE_XLAT) &&
+ (!pass2_xlat_compile(cf_sectiontoitem(g->cs),
+ &g->vpt, true))) {
+ return false;
+ }
+
+ if (!modcall_pass2(g->children)) return false;
+ g->done_pass2 = true;
+ break;
+
+ case MOD_FOREACH:
+ g = mod_callabletogroup(this);
+ if (g->done_pass2) return true;
+
+ /*
+ * Already parsed, handle the children.
+ */
+ if (g->vpt) goto check_children;
+
+ /*
+ * We had &Foo-Bar, where Foo-Bar is
+ * defined by a module.
+ */
+ rad_assert(this->name != NULL);
+ rad_assert(this->name[0] == '&');
+ rad_assert(cf_section_name2_type(g->cs) == T_BARE_WORD);
+
+ /*
+ * The statement may refer to an
+ * attribute which doesn't exist until
+ * all of the modules have been loaded.
+ * Check for that now.
+ */
+ g->vpt = radius_str2tmpl(g->cs, this->name,
+ cf_section_name2_type(g->cs),
+ REQUEST_CURRENT, PAIR_LIST_REQUEST);
+ if (!g->vpt) {
+ cf_log_err_cs(g->cs, "Syntax error in '%s': %s",
+ this->name, fr_strerror());
+ return false;
+ }
+
+ check_children:
+ rad_assert(g->vpt->type == VPT_TYPE_ATTR);
+ if (g->vpt->vpt_num != NUM_ANY) {
+ cf_log_err_cs(g->cs, "MUST NOT use array references in 'foreach'");
+ return false;
+ }
+ if (!modcall_pass2(g->children)) return false;
+ g->done_pass2 = true;
+ break;
+
+ case MOD_ELSE:
+ case MOD_POLICY:
/* FALL-THROUGH */
#endif
case MOD_GROUP:
case MOD_LOAD_BALANCE:
case MOD_REDUNDANT_LOAD_BALANCE:
+ g = mod_callabletogroup(this);
+ if (g->done_pass2) return true;
+ if (!modcall_pass2(g->children)) return false;
+ g->done_pass2 = true;
+ break;
+ }
+ }
+
+ return true;
+}
+
+void modcall_debug(modcallable *mc, int depth)
+{
+ modcallable *this;
+ modgroup *g;
+ value_pair_map_t *map;
+ const char *name1;
+ char buffer[1024];
+
+ for (this = mc; this != NULL; this = this->next) {
+ switch (this->type) {
+ default:
+ break;
+
+ case MOD_SINGLE: {
+ modsingle *single = mod_callabletosingle(this);
+
+ DEBUG("%.*s%s", depth, modcall_spaces,
+ single->modinst->name);
+ }
+ break;
#ifdef WITH_UNLANG
+ case MOD_UPDATE:
+ g = mod_callabletogroup(this);
+ DEBUG("%.*s%s {", depth, modcall_spaces,
+ group_name[this->type]);
+
+ for (map = g->map; map != NULL; map = map->next) {
+ radius_map2str(buffer, sizeof(buffer), map);
+ DEBUG("%.*s%s", depth + 1, modcall_spaces, buffer);
+ }
+
+ DEBUG("%.*s}", depth, modcall_spaces);
+ break;
+
case MOD_ELSE:
+ g = mod_callabletogroup(this);
+ DEBUG("%.*s%s {", depth, modcall_spaces,
+ group_name[this->type]);
+ modcall_debug(g->children, depth + 1);
+ DEBUG("%.*s}", depth, modcall_spaces);
+ break;
+
+ case MOD_IF:
+ case MOD_ELSIF:
+ g = mod_callabletogroup(this);
+ fr_cond_sprint(buffer, sizeof(buffer), g->cond);
+ DEBUG("%.*s%s (%s) {", depth, modcall_spaces,
+ group_name[this->type], buffer);
+ modcall_debug(g->children, depth + 1);
+ DEBUG("%.*s}", depth, modcall_spaces);
+ break;
+
case MOD_SWITCH:
case MOD_CASE:
- case MOD_FOREACH:
+ g = mod_callabletogroup(this);
+ radius_tmpl2str(buffer, sizeof(buffer), g->vpt);
+ DEBUG("%.*s%s %s {", depth, modcall_spaces,
+ group_name[this->type], buffer);
+ modcall_debug(g->children, depth + 1);
+ DEBUG("%.*s}", depth, modcall_spaces);
+ break;
+
case MOD_POLICY:
+ case MOD_FOREACH:
+ g = mod_callabletogroup(this);
+ DEBUG("%.*s%s %s {", depth, modcall_spaces,
+ group_name[this->type], this->name);
+ modcall_debug(g->children, depth + 1);
+ DEBUG("%.*s}", depth, modcall_spaces);
+ break;
+
+ case MOD_BREAK:
+ DEBUG("%.*sbreak", depth, modcall_spaces);
+ break;
+
#endif
+ case MOD_GROUP:
g = mod_callabletogroup(this);
- if (!modcall_pass2(g->children)) return false;
+ name1 = cf_section_name1(g->cs);
+ if (strcmp(name1, "group") == 0) {
+ DEBUG("%.*s%s {", depth, modcall_spaces,
+ group_name[this->type]);
+ } else {
+ DEBUG("%.*s%s %s {", depth, modcall_spaces,
+ name1, cf_section_name2(g->cs));
+ }
+ modcall_debug(g->children, depth + 1);
+ DEBUG("%.*s}", depth, modcall_spaces);
+ break;
+
+
+ case MOD_LOAD_BALANCE:
+ case MOD_REDUNDANT_LOAD_BALANCE:
+ g = mod_callabletogroup(this);
+ DEBUG("%.*s%s {", depth, modcall_spaces,
+ group_name[this->type]);
+ modcall_debug(g->children, depth + 1);
+ DEBUG("%.*s}", depth, modcall_spaces);
break;
}
}
-
- return true;
}
#define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
#endif
+/** Check if the magic number in the module matches the one in the library
+ *
+ * This is used to detect potential ABI issues caused by running with modules which
+ * were built for a different version of the server.
+ *
+ * @param cs being parsed.
+ * @param module being loaded.
+ * @returns 0 on success, -1 if prefix mismatch, -2 if version mismatch, -3 if commit mismatch.
+ */
+static int check_module_magic(CONF_SECTION *cs, module_t const *module)
+{
+ if (MAGIC_PREFIX(module->magic) != MAGIC_PREFIX(RADIUSD_MAGIC_NUMBER)) {
+ cf_log_err_cs(cs, "Application and rlm_%s magic number (prefix) mismatch."
+ " application: %x module: %x", module->name,
+ MAGIC_PREFIX(RADIUSD_MAGIC_NUMBER),
+ MAGIC_PREFIX(module->magic));
+ return -1;
+ }
+
+ if (MAGIC_VERSION(module->magic) != MAGIC_VERSION(RADIUSD_MAGIC_NUMBER)) {
+ cf_log_err_cs(cs, "Application and rlm_%s magic number (version) mismatch."
+ " application: %lx module: %lx", module->name,
+ (unsigned long) MAGIC_VERSION(RADIUSD_MAGIC_NUMBER),
+ (unsigned long) MAGIC_VERSION(module->magic));
+ return -2;
+ }
+
+ if (MAGIC_COMMIT(module->magic) != MAGIC_COMMIT(RADIUSD_MAGIC_NUMBER)) {
+ cf_log_err_cs(cs, "Application and rlm_%s magic number (commit) mismatch."
+ " application: %lx module: %lx", module->name,
+ (unsigned long) MAGIC_COMMIT(RADIUSD_MAGIC_NUMBER),
+ (unsigned long) MAGIC_COMMIT(module->magic));
+ return -3;
+ }
+
+ return 0;
+}
+
/*
* Because dlopen produces really shitty and inaccurate error messages
*/
{
if (access(name, R_OK) < 0) switch (errno) {
case EACCES:
- WDEBUG("Library \"%s\" exists, but we don't have permission to read", name);
+ WARN("Library \"%s\" exists, but we don't have permission to read", name);
break;
case ENOENT:
DEBUG4("Library not found at path \"%s\"", name);
break;
default:
- DEBUG4("Possible issue accessing Library \"%s\": %s", name, strerror(errno));
+ DEBUG4("Possible issue accessing Library \"%s\": %s", name, fr_syserror(errno));
break;
}
}
int flags = RTLD_NOW;
void *handle;
char buffer[2048];
+ char *env;
#ifdef RTLD_GLOBAL
if (strcmp(name, "rlm_perl") == 0) {
#endif
flags |= RTLD_LOCAL;
+#ifndef NDEBUG
+ /*
+ * Bind all the symbols *NOW* so we don't hit errors later
+ */
+ flags |= RTLD_NOW;
+#endif
/*
* Prefer loading our libraries by absolute path.
*/
snprintf(buffer, sizeof(buffer), "%s/%s%s", radlib_dir, name, LT_SHREXT);
- check_lib_access(buffer);
+ DEBUG4("Loading library using absolute path");
handle = dlopen(buffer, flags);
- if (handle) return handle;
+ if (handle) {
+ return handle;
+ }
+ check_lib_access(buffer);
- strlcpy(buffer, name, sizeof(buffer));
+ DEBUG4("Falling back to linker search path(s)");
+ if (DEBUG_ENABLED4) {
+#ifdef __APPLE__
+ env = getenv("LD_LIBRARY_PATH");
+ if (env) {
+ DEBUG4("LD_LIBRARY_PATH : %s", env);
+ }
+ env = getenv("DYLD_LIBRARY_PATH");
+ if (env) {
+ DEBUG4("DYLB_LIBRARY_PATH : %s", env);
+ }
+ env = getenv("DYLD_FALLBACK_LIBRARY_PATH");
+ if (env) {
+ DEBUG4("DYLD_FALLBACK_LIBRARY_PATH : %s", env);
+ }
+ env = getcwd(buffer, sizeof(buffer));
+ if (env) {
+ DEBUG4("Current directory : %s", env);
+ }
+#else
+ env = getenv("LD_LIBRARY_PATH");
+ if (env) {
+ DEBUG4("LD_LIBRARY_PATH : %s", env);
+ }
+ DEBUG4("Defaults : /lib:/usr/lib");
+#endif
+ }
+ strlcpy(buffer, name, sizeof(buffer));
/*
* FIXME: Make this configurable...
*/
* debugging. This removes the symbols needed by
* valgrind.
*/
- if (!mainconfig.debug_memory)
+ if (!main_config.debug_memory)
#endif
dlclose(this->handle); /* ignore any errors */
return 0;
/*
* Remove the module lists.
*/
-int detach_modules(void)
+int modules_free(void)
{
rbtree_free(instance_tree);
rbtree_free(module_tree);
/*
* Before doing anything else, check if it's sane.
*/
- if (module->magic != RLM_MODULE_MAGIC_NUMBER) {
+ if (check_module_magic(cs, module) < 0) {
dlclose(handle);
- cf_log_err_cs(cs,
- "Invalid version in module '%s'",
- module_name);
return NULL;
-
}
/* make room for the module type */
}
if (check_config && (node->entry->module->instantiate) &&
- (node->entry->module->type & RLM_TYPE_CHECK_CONFIG_SAFE) == 0) {
+ (node->entry->module->type & RLM_TYPE_CHECK_CONFIG_UNSAFE) != 0) {
char const *value = NULL;
CONF_PAIR *cp;
if (idx == 0) {
list = server->mc[comp];
- if (!list) RWDEBUG2("Empty %s section. Using default return values.", section_type_value[comp].section);
+ if (!list) RDEBUG3("Empty %s section. Using default return values.", section_type_value[comp].section);
} else {
indexed_modcallable *this;
if (this) {
list = this->modulelist;
} else {
- RWDEBUG2("Unknown value specified for %s. Cannot perform requested action.",
+ RDEBUG3("%s sub-section not found. Ignoring.",
section_type_value[comp].typename);
}
}
*/
static int load_subcomponent_section(modcallable *parent, CONF_SECTION *cs,
rbtree_t *components,
- DICT_ATTR const *dattr, rlm_components_t comp)
+ DICT_ATTR const *da, rlm_components_t comp)
{
indexed_modcallable *subcomp;
modcallable *ml;
* automatically. If it isn't found, it's a serious
* error.
*/
- dval = dict_valbyname(dattr->attr, dattr->vendor, name2);
+ dval = dict_valbyname(da->attr, da->vendor, name2);
if (!dval) {
cf_log_err_cs(cs,
"%s %s Not previously configured",
return 1; /* OK */
}
-static int define_type(CONF_SECTION *cs, DICT_ATTR const *dattr, char const *name)
+static int define_type(CONF_SECTION *cs, DICT_ATTR const *da, char const *name)
{
uint32_t value;
DICT_VALUE *dval;
* If the value already exists, don't
* create it again.
*/
- dval = dict_valbyname(dattr->attr, dattr->vendor, name);
+ dval = dict_valbyname(da->attr, da->vendor, name);
if (dval) return 1;
/*
*/
do {
value = fr_rand() & 0x00ffffff;
- } while (dict_valbyattr(dattr->attr, dattr->vendor, value));
+ } while (dict_valbyattr(da->attr, da->vendor, value));
- cf_log_module(cs, "Creating %s = %s", dattr->name, name);
- if (dict_addvalue(name, dattr->name, value) < 0) {
+ cf_log_module(cs, "Creating %s = %s", da->name, name);
+ if (dict_addvalue(name, da->name, value) < 0) {
ERROR("%s", fr_strerror());
return 0;
}
return 1;
}
+/*
+ * Don't complain too often.
+ */
+#define MAX_IGNORED (32)
+static int last_ignored = -1;
+static char const *ignored[MAX_IGNORED];
+
static int load_component_section(CONF_SECTION *cs,
rbtree_t *components, rlm_components_t comp)
{
int idx;
indexed_modcallable *subcomp;
char const *modname;
- char const *visiblename;
- DICT_ATTR const *dattr;
+ DICT_ATTR const *da;
/*
* Find the attribute used to store VALUEs for this section.
*/
- dattr = dict_attrbyvalue(section_type_value[comp].attr, 0);
- if (!dattr) {
+ da = dict_attrbyvalue(section_type_value[comp].attr, 0);
+ if (!da) {
cf_log_err_cs(cs,
"No such attribute %s",
section_type_value[comp].typename);
section_type_value[comp].typename) == 0) {
if (!load_subcomponent_section(NULL, scs,
components,
- dattr,
+ da,
comp)) {
+
return -1; /* FIXME: memleak? */
}
continue;
cp = NULL;
- /*
- * Skip commented-out sections.
- *
- * We skip an "if" ONLY when there's no
- * "else" after it, as the run-time
- * interpretor needs the results of the
- * previous "if".
- */
- if (strcmp(name1, "if") == 0) {
- fr_cond_t const *c;
- CONF_ITEM *next_ci;
-
- next_ci = cf_item_find_next(scs, modref);
- if (next_ci && cf_item_is_section(next_ci)) {
- char const *next_name;
- CONF_SECTION *next_cs;
-
- next_cs = cf_itemtosection(next_ci);
- next_name = cf_section_name1(next_cs);
- if ((strcmp(next_name, "else") == 0) ||
- (strcmp(next_name, "elseif") == 0)) {
- c = NULL;
- } else {
- c = cf_data_find(scs, "if");
- }
- } else {
- c = cf_data_find(scs, "if");
- }
-
- if (c && c->type == COND_TYPE_FALSE) {
- DEBUG(" # Skipping contents of '%s' at %s:%d as it statically evaluates to 'false'",
- name1, cf_section_filename(scs), cf_section_lineno(scs));
- continue;
- }
- }
-
-
} else if (cf_item_is_pair(modref)) {
cp = cf_itemtopair(modref);
}
/*
- * Try to compile one entry.
- */
- this = compile_modsingle(NULL, comp, modref, &modname);
-
- /*
- * It's OK for the module to not exist.
- */
- if (!this && modname && (modname[0] == '-')) {
- WDEBUG("Ignoring \"%s\" (see raddb/mods-available/README.rst)", modname + 1);
- continue;
- }
-
- if (!this) {
- cf_log_err_cs(cs,
- "Errors parsing %s section.\n",
- cf_section_name1(cs));
- return -1;
- }
-
- /*
* Look for Auth-Type foo {}, which are special
* cases of named sections, and allowable ONLY
* at the top-level.
} else {
modrefname = cf_section_name2(scs);
if (!modrefname) {
- modcallable_free(&this);
cf_log_err_cs(cs,
"Errors parsing %s sub-section.\n",
cf_section_name1(scs));
* It's a section, but nothing we
* recognize. Die!
*/
- modcallable_free(&this);
cf_log_err_cs(cs,
"Unknown Auth-Type \"%s\" in %s sub-section.",
modrefname, section_type_value[comp].section);
}
subcomp = new_sublist(cs, components, comp, idx);
- if (subcomp == NULL) {
- modcallable_free(&this);
+ if (!subcomp) continue;
+
+ /*
+ * Try to compile one entry.
+ */
+ this = compile_modsingle(&subcomp->modulelist, comp, modref, &modname);
+
+ /*
+ * It's OK for the module to not exist.
+ */
+ if (!this && modname && (modname[0] == '-')) {
+ int i;
+
+ if (last_ignored < 0) {
+ save_complain:
+ last_ignored++;
+ ignored[last_ignored] = modname;
+
+ complain:
+ WARN("Ignoring \"%s\" (see raddb/mods-available/README.rst)", modname + 1);
+ continue;
+ }
+
+ if (last_ignored >= MAX_IGNORED) goto complain;
+
+ for (i = 0; i <= last_ignored; i++) {
+ if (strcmp(ignored[i], modname) == 0) {
+ break;
+ }
+ }
+
+ if (i > last_ignored) goto save_complain;
continue;
}
- /* If subcomp->modulelist is NULL, add_to_modcallable will
- * create it */
- visiblename = cf_section_name2(cs);
- if (visiblename == NULL)
- visiblename = cf_section_name1(cs);
- add_to_modcallable(&subcomp->modulelist, this,
- comp, visiblename);
+ if (!this) {
+ cf_log_err_cs(cs,
+ "Errors parsing %s section.\n",
+ cf_section_name1(cs));
+ return -1;
+ }
+
+ if (debug_flag > 2) modcall_debug(this, 2);
+
+ add_to_modcallable(subcomp->modulelist, this);
}
+
return 0;
}
for (comp = 0; comp < RLM_COMPONENT_COUNT; ++comp) {
CONF_SECTION *subcs;
CONF_ITEM *modref;
- DICT_ATTR const *dattr;
+ DICT_ATTR const *da;
subcs = cf_section_sub_find(cs,
section_type_value[comp].section);
/*
* Find the attribute used to store VALUEs for this section.
*/
- dattr = dict_attrbyvalue(section_type_value[comp].attr, 0);
- if (!dattr) {
+ da = dict_attrbyvalue(section_type_value[comp].attr, 0);
+ if (!da) {
cf_log_err_cs(subcs,
"No such attribute %s",
section_type_value[comp].typename);
if ((section_type_value[comp].attr == PW_AUTH_TYPE) &&
cf_item_is_pair(modref)) {
CONF_PAIR *cp = cf_itemtopair(modref);
- if (!define_type(cs, dattr, cf_pair_attr(cp))) {
+ if (!define_type(cs, da, cf_pair_attr(cp))) {
goto error;
}
name1 = cf_section_name1(subsubcs);
if (strcmp(name1, section_type_value[comp].typename) == 0) {
- if (!define_type(cs, dattr,
+ if (!define_type(cs, da,
cf_section_name2(subsubcs))) {
goto error;
}
if (cf_item_find_next(subcs, NULL) == NULL) continue;
- cf_log_module(cs, "Loading %s {...}",
- section_type_value[comp].section);
-
/*
* Skip pre/post-proxy sections if we're not
* proxying.
*/
if (
#ifdef WITH_PROXY
- !mainconfig.proxy_requests &&
+ !main_config.proxy_requests &&
#endif
((comp == RLM_COMPONENT_PRE_PROXY) ||
(comp == RLM_COMPONENT_POST_PROXY))) {
if (comp == RLM_COMPONENT_SESS) continue;
#endif
+ if (debug_flag <= 3) {
+ cf_log_module(cs, "Loading %s {...}",
+ section_type_value[comp].section);
+ } else {
+ DEBUG(" %s {", section_type_value[comp].section);
+ }
+
if (load_component_section(subcs, components, comp) < 0) {
goto error;
}
+ if (debug_flag > 3) {
+ DEBUG(" } # %s", section_type_value[comp].section);
+ }
+
/*
* Cache a default, if it exists. Some people
* put empty sections for some reason...
* This is a bit of a hack...
*/
if (!found) do {
+#if defined(WITH_VMPS) || defined(WITH_DHCP)
CONF_SECTION *subcs;
+#endif
#ifdef WITH_DHCP
- DICT_ATTR const *dattr;
+ DICT_ATTR const *da;
#endif
+#ifdef WITH_VMPS
subcs = cf_section_sub_find(cs, "vmps");
if (subcs) {
- cf_log_module(cs, "Checking vmps {...} for more modules to load");
+ cf_log_module(cs, "Loading vmps {...}");
if (load_component_section(subcs, components,
RLM_COMPONENT_POST_AUTH) < 0) {
goto error;
found = 1;
break;
}
+#endif
#ifdef WITH_DHCP
+ /*
+ * It's OK to not have DHCP.
+ */
subcs = cf_subsection_find_next(cs, NULL, "dhcp");
- dattr = dict_attrbyname("DHCP-Message-Type");
- if (!dattr && subcs) {
- cf_log_err_cs(subcs, "Found a 'dhcp' section, but no DHCP dictionaries have been loaded");
- goto error;
- }
+ if (!subcs) break;
- if (!dattr) break;
+ da = dict_attrbyname("DHCP-Message-Type");
/*
* Handle each DHCP Message type separately.
while (subcs) {
char const *name2 = cf_section_name2(subcs);
- DEBUG2(" Module: Checking dhcp %s {...} for more modules to load", name2);
+ if (name2) {
+ cf_log_module(cs, "Loading dhcp %s {...}", name2);
+ } else {
+ cf_log_module(cs, "Loading dhcp {...}");
+ }
if (!load_subcomponent_section(NULL, subcs,
components,
- dattr,
+ da,
RLM_COMPONENT_POST_AUTH)) {
goto error; /* FIXME: memleak? */
}
}
if (!found && name) {
- WDEBUG("Server %s is empty, and will do nothing!",
+ WARN("Server %s is empty, and will do nothing!",
name);
}
}
+static int pass2_cb(UNUSED void *ctx, void *data)
+{
+ indexed_modcallable *this = data;
+
+ if (!modcall_pass2(this->modulelist)) return -1;
+
+ return 0;
+}
+
/*
* Load all of the virtual servers.
*/
{
CONF_SECTION *cs;
virtual_server_t *server;
- static int first_time = true;
+ static bool first_time = true;
- DEBUG2("%s: #### Loading Virtual Servers ####", mainconfig.name);
+ DEBUG2("%s: #### Loading Virtual Servers ####", main_config.name);
/*
* If we have "server { ...}", then there SHOULD NOT be
for (i = RLM_COMPONENT_AUTH; i < RLM_COMPONENT_COUNT; i++) {
if (!modcall_pass2(server->mc[i])) return -1;
+
+ }
+
+ if (server->components &&
+ (rbtree_walk(server->components, RBTREE_IN_ORDER,
+ pass2_cb, NULL) != 0)) {
+ return -1;
}
}
}
-int module_hup(CONF_SECTION *modules)
+int modules_hup(CONF_SECTION *modules)
{
time_t when;
CONF_ITEM *ci;
/*
* Parse the module config sections, and load
* and call each module's init() function.
- *
- * Libtool makes your life a LOT easier, especially with libltdl.
- * see: http://www.gnu.org/software/libtool/
*/
-int setup_modules(int reload, CONF_SECTION *config)
+int modules_init(CONF_SECTION *config)
{
CONF_ITEM *ci, *next;
CONF_SECTION *cs, *modules;
rad_listen_t *listener;
- if (reload) return 0;
-
/*
- * If necessary, initialize libltdl.
+ * Set up the internal module struct.
*/
- if (!reload) {
- /*
- * Set up the internal module struct.
- */
- module_tree = rbtree_create(module_entry_cmp, NULL, 0);
- if (!module_tree) {
- ERROR("Failed to initialize modules\n");
- return -1;
- }
+ module_tree = rbtree_create(module_entry_cmp, NULL, 0);
+ if (!module_tree) {
+ ERROR("Failed to initialize modules\n");
+ return -1;
+ }
- instance_tree = rbtree_create(module_instance_cmp,
- module_instance_free, 0);
- if (!instance_tree) {
- ERROR("Failed to initialize modules\n");
- return -1;
- }
+ instance_tree = rbtree_create(module_instance_cmp,
+ module_instance_free, 0);
+ if (!instance_tree) {
+ ERROR("Failed to initialize modules\n");
+ return -1;
}
memset(virtual_servers, 0, sizeof(virtual_servers));
WARN("Cannot find a \"modules\" section in the configuration file!");
}
- DEBUG2("%s: #### Instantiating modules ####", mainconfig.name);
+#if defined(WITH_VMPS) || defined(WITH_DHCP)
+ /*
+ * Load dictionaries.
+ */
+ for (cs = cf_subsection_find_next(config, NULL, "server");
+ cs != NULL;
+ cs = cf_subsection_find_next(config, cs, "server")) {
+ CONF_SECTION *subcs;
+ DICT_ATTR const *da;
+
+#ifdef WITH_VMPS
+ /*
+ * Auto-load the VMPS/VQP dictionary.
+ */
+ subcs = cf_section_sub_find(cs, "vmps");
+ if (subcs) {
+ da = dict_attrbyname("VQP-Packet-Type");
+ if (!da) {
+ if (dict_read(main_config.dictionary_dir, "dictionary.vqp") < 0) {
+ ERROR("Failed reading dictionary.vqp: %s",
+ fr_strerror());
+ return -1;
+ }
+ cf_log_module(cs, "Loading dictionary.vqp");
+
+ da = dict_attrbyname("VQP-Packet-Type");
+ if (!da) {
+ ERROR("No VQP-Packet-Type in dictionary.vqp");
+ return -1;
+ }
+ }
+ }
+#endif
+
+#ifdef WITH_DHCP
+ /*
+ * Auto-load the DHCP dictionary.
+ */
+ subcs = cf_subsection_find_next(cs, NULL, "dhcp");
+ if (subcs) {
+ da = dict_attrbyname("DHCP-Message-Type");
+ if (!da) {
+ cf_log_module(cs, "Loading dictionary.dhcp");
+ if (dict_read(main_config.dictionary_dir, "dictionary.dhcp") < 0) {
+ ERROR("Failed reading dictionary.dhcp: %s",
+ fr_strerror());
+ return -1;
+ }
+
+ da = dict_attrbyname("DHCP-Message-Type");
+ if (!da) {
+ ERROR("No DHCP-Message-Type in dictionary.dhcp");
+ return -1;
+ }
+ }
+ }
+#endif
+ /*
+ * Else it's a RADIUS virtual server, and the
+ * dictionaries are already loaded.
+ */
+ }
+#endif
+
+ DEBUG2("%s: #### Instantiating modules ####", main_config.name);
/*
* Loop over module definitions, looking for duplicates.
* Loop over the listeners, figuring out which sections
* to load.
*/
- for (listener = mainconfig.listen;
+ for (listener = main_config.listen;
listener != NULL;
listener = listener->next) {
char buffer[256];
#define PW_CAST_BASE (1850)
+static const FR_NAME_NUMBER allowed_return_codes[] = {
+ { "reject", 1 },
+ { "fail", 1 },
+ { "ok", 1 },
+ { "handled", 1 },
+ { "invalid", 1 },
+ { "userlock", 1 },
+ { "notfound", 1 },
+ { "noop", 1 },
+ { "updated", 1 },
+ { NULL, 0 }
+};
+
/*
* This file shouldn't use any functions from the server core.
*/
-size_t fr_cond_sprint(char *buffer, size_t bufsize, fr_cond_t const *c)
+size_t fr_cond_sprint(char *buffer, size_t bufsize, fr_cond_t const *in)
{
size_t len;
char *p = buffer;
char *end = buffer + bufsize - 1;
+ fr_cond_t const *c = in;
next:
if (c->negate) {
}
-/*
- * Cast a literal vpt to a value_data_t
- */
-static int cast_vpt(value_pair_tmpl_t *vpt, DICT_ATTR const *da)
-{
- VALUE_PAIR *vp;
- value_data_t *data;
-
- rad_assert(vpt->type == VPT_TYPE_LITERAL);
-
- vp = pairalloc(vpt, da);
- if (!vp) return false;
-
- if (!pairparsevalue(vp, vpt->name)) {
- pairfree(&vp);
- return false;
- }
-
- vpt->length = vp->length;
- vpt->vpd = data = talloc(vpt, value_data_t);
- if (!vpt->vpd) return false;
-
- vpt->type = VPT_TYPE_DATA;
- vpt->da = da;
-
- if (vp->da->flags.is_pointer) {
- data->ptr = talloc_steal(vpt, vp->data.ptr);
- vp->data.ptr = NULL;
- } else {
- memcpy(data, &vp->data, sizeof(*data));
- }
-
- pairfree(&vp);
-
- return true;
-}
-
static ssize_t condition_tokenize_string(TALLOC_CTX *ctx, char const *start, char **out,
FR_TOKEN *op, char const **error)
{
return -(p - start);
}
+ /*
+ * We can only cast to basic data types. Complex ones
+ * are forbidden.
+ */
+ switch (cast) {
+#ifdef WITH_ASCEND_BINARY
+ case PW_TYPE_ABINARY:
+#endif
+ case PW_TYPE_IP_ADDR:
+ case PW_TYPE_TLV:
+ case PW_TYPE_EXTENDED:
+ case PW_TYPE_LONG_EXTENDED:
+ case PW_TYPE_EVS:
+ case PW_TYPE_VSA:
+ *error = "Forbidden data type in cast";
+ return -(p - start);
+
+ default:
+ break;
+ }
+
*pda = dict_attrbyvalue(PW_CAST_BASE + cast, 0);
if (!*pda) {
*error = "Cannot cast to this data type";
* @param[out] error the parse error (if any)
* @return length of the string skipped, or when negative, the offset to the offending error
*/
-static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, int brace, fr_cond_t **pcond, char const **error, int flags)
+static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, int brace,
+ fr_cond_t **pcond, char const **error, int flags)
{
ssize_t slen;
char const *p = start;
rad_assert(c != NULL);
lhs = rhs = NULL;
+ lhs_type = rhs_type = T_OP_INVALID;
while (isspace((int) *p)) p++; /* skip spaces before condition */
* brackets. Go recurse to get more.
*/
c->type = COND_TYPE_CHILD;
+ c->ci = ci;
slen = condition_tokenize(c, ci, p, true, &c->data.child, error, flags);
if (slen <= 0) {
return_SLEN;
return_0("Cannot do cast for existence check");
}
- if (lhs_type == T_BARE_WORD) {
- if ((strcmp(lhs, "true") == 0) ||
- ((lhs[0] == '1') && !lhs[1])) {
- c->type = COND_TYPE_TRUE;
-
- } else if ((strcmp(lhs, "false") == 0) ||
- ((lhs[0] == '0') && !lhs[1])) {
- c->type = COND_TYPE_FALSE;
-
- } else {
- goto create_exists;
- }
+ c->type = COND_TYPE_EXISTS;
+ c->ci = ci;
- } else {
- create_exists:
- c->type = COND_TYPE_EXISTS;
- c->data.vpt = radius_str2tmpl(c, lhs, lhs_type);
- if (!c->data.vpt) {
- return_P("Failed creating exists");
- }
+ c->data.vpt = radius_str2tmpl(c, lhs, lhs_type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
+ if (!c->data.vpt) {
+ return_P("Failed creating exists");
}
+ rad_assert(c->data.vpt->type != VPT_TYPE_REGEX);
+
} else { /* it's an operator */
- int regex;
+ bool regex;
+ bool i_flag = false;
/*
* The next thing should now be a comparison operator.
*/
regex = false;
c->type = COND_TYPE_MAP;
+ c->ci = ci;
+
switch (*p) {
default:
return_P("Invalid text. Expected comparison operator");
* Allow /foo/i
*/
if (p[slen] == 'i') {
- c->regex_i = true;
+ i_flag = true;
slen++;
}
c->data.map = radius_str2map(c, lhs, lhs_type, op, rhs, rhs_type,
REQUEST_CURRENT, PAIR_LIST_REQUEST,
REQUEST_CURRENT, PAIR_LIST_REQUEST);
-
if (!c->data.map) {
+ /*
+ * FIXME: if strings are T_BARE_WORD and they start with '&',
+ * then they refer to attributes which have not yet been
+ * defined. Create the template(s) as literals, and
+ * fix them up in pass2.
+ */
+ if (*lhs == '&') {
+ return_0("Unknown attribute");
+ }
return_0("Syntax error");
}
+ if (c->data.map->src->type == VPT_TYPE_REGEX) {
+ c->data.map->src->vpt_iflag = i_flag;
+ }
+
/*
* Could have been a reference to an attribute which is registered later.
* Mark it as being checked in pass2.
c->data.map->ci = ci;
/*
- * foo =* bar is just (foo)
- * foo !* bar is just (!foo)
- */
- if ((op == T_OP_CMP_TRUE) || (op == T_OP_CMP_FALSE)) {
- value_pair_tmpl_t *vpt;
-
- vpt = talloc_steal(c, c->data.map->dst);
- c->data.map->dst = NULL;
-
- talloc_free(c->data.map);
- c->type = COND_TYPE_EXISTS;
- c->data.vpt = vpt;
-
- /*
- * Invert the negation bit.
- */
- if (op == T_OP_CMP_FALSE) {
- c->negate = !c->negate;
- }
-
- goto done_cond;
- }
-
- /*
* @todo: check LHS and RHS separately, to
* get better errors
*/
*/
if (c->cast) {
if ((c->data.map->src->type == VPT_TYPE_ATTR) &&
- (c->cast->type != c->data.map->src->da->type)) {
+ (c->cast->type != c->data.map->src->vpt_da->type)) {
goto same_type;
}
* Cast it to the appropriate data type.
*/
if ((c->data.map->dst->type == VPT_TYPE_LITERAL) &&
- !cast_vpt(c->data.map->dst, c->cast)) {
+ !radius_cast_tmpl(c->data.map->dst, c->cast)) {
*error = "Failed to parse field";
if (lhs) talloc_free(lhs);
if (rhs) talloc_free(rhs);
*/
if ((c->data.map->dst->type == VPT_TYPE_DATA) &&
(c->data.map->src->type == VPT_TYPE_LITERAL) &&
- !cast_vpt(c->data.map->src, c->data.map->dst->da)) {
+ !radius_cast_tmpl(c->data.map->src, c->data.map->dst->vpt_da)) {
return_rhs("Failed to parse field");
}
/*
+ * We may be casting incompatible
+ * types. We check this based on
+ * their size.
+ */
+ if (c->data.map->dst->type == VPT_TYPE_ATTR) {
+ /*
+ * dst.min == src.min
+ * dst.max == src.max
+ */
+ if ((dict_attr_sizes[c->cast->type][0] == dict_attr_sizes[c->data.map->dst->vpt_da->type][0]) &&
+ (dict_attr_sizes[c->cast->type][1] == dict_attr_sizes[c->data.map->dst->vpt_da->type][1])) {
+ goto cast_ok;
+ }
+
+ /*
+ * Run-time parsing of strings.
+ * Run-time copying of octets.
+ */
+ if ((c->data.map->dst->vpt_da->type == PW_TYPE_STRING) ||
+ (c->data.map->dst->vpt_da->type == PW_TYPE_OCTETS)) {
+ goto cast_ok;
+ }
+
+ /*
+ * ipaddr to ipv4prefix is OK
+ */
+ if ((c->data.map->dst->vpt_da->type == PW_TYPE_IPV4_ADDR) &&
+ (c->cast->type == PW_TYPE_IPV4_PREFIX)) {
+ goto cast_ok;
+ }
+
+ /*
+ * ipv6addr to ipv6prefix is OK
+ */
+ if ((c->data.map->dst->vpt_da->type == PW_TYPE_IPV6_ADDR) &&
+ (c->cast->type == PW_TYPE_IPV6_PREFIX)) {
+ goto cast_ok;
+ }
+
+ /*
+ * integer64 to ethernet is OK.
+ */
+ if ((c->data.map->dst->vpt_da->type == PW_TYPE_INTEGER64) &&
+ (c->cast->type == PW_TYPE_ETHERNET)) {
+ goto cast_ok;
+ }
+
+ /*
+ * dst.max < src.min
+ * dst.min > src.max
+ */
+ if ((dict_attr_sizes[c->cast->type][1] < dict_attr_sizes[c->data.map->dst->vpt_da->type][0]) ||
+ (dict_attr_sizes[c->cast->type][0] > dict_attr_sizes[c->data.map->dst->vpt_da->type][1])) {
+ return_0("Cannot cast to attribute of incompatible size");
+ }
+ }
+
+ cast_ok:
+ /*
* Casting to a redundant type means we don't need the cast.
*
* Do this LAST, as the rest of the code above assumes c->cast
* is not NULL.
*/
if ((c->data.map->dst->type == VPT_TYPE_ATTR) &&
- (c->cast->type == c->data.map->dst->da->type)) {
+ (c->cast->type == c->data.map->dst->vpt_da->type)) {
c->cast = NULL;
}
*/
if ((c->data.map->src->type == VPT_TYPE_ATTR) &&
(c->data.map->dst->type == VPT_TYPE_ATTR) &&
- (c->data.map->dst->da->type != c->data.map->src->da->type)) {
+ (c->data.map->dst->vpt_da->type != c->data.map->src->vpt_da->type)) {
same_type:
- return_0("Attribute comparisons must be of the same attribute type");
+ return_0("Attribute comparisons must be of the same data type");
}
/*
/*
* Invalid: User-Name == bob
* Valid: User-Name == "bob"
+ *
+ * There's no real reason for
+ * this, other than consistency.
*/
if ((c->data.map->dst->type == VPT_TYPE_ATTR) &&
(c->data.map->src->type != VPT_TYPE_ATTR) &&
- (c->data.map->dst->da->type == PW_TYPE_STRING) &&
+ (c->data.map->dst->vpt_da->type == PW_TYPE_STRING) &&
+ (c->data.map->op != T_OP_CMP_TRUE) &&
+ (c->data.map->op != T_OP_CMP_FALSE) &&
(rhs_type == T_BARE_WORD)) {
return_rhs("Must have string as value for attribute");
}
*/
if ((c->data.map->dst->type == VPT_TYPE_ATTR) &&
(c->data.map->src->type != VPT_TYPE_ATTR) &&
- (c->data.map->dst->da->type != PW_TYPE_STRING) &&
- (c->data.map->dst->da->type != PW_TYPE_OCTETS) &&
- (c->data.map->dst->da->type != PW_TYPE_DATE) &&
+ (c->data.map->dst->vpt_da->type != PW_TYPE_STRING) &&
+ (c->data.map->dst->vpt_da->type != PW_TYPE_OCTETS) &&
+ (c->data.map->dst->vpt_da->type != PW_TYPE_DATE) &&
(rhs_type == T_SINGLE_QUOTED_STRING)) {
*error = "Value must be an unquoted string";
return_rhs:
* literal. Cast the RHS to the type of the cast.
*/
if (c->cast && (c->data.map->src->type == VPT_TYPE_LITERAL) &&
- !cast_vpt(c->data.map->src, c->cast)) {
+ !radius_cast_tmpl(c->data.map->src, c->cast)) {
return_rhs("Failed to parse field");
}
*/
if ((c->data.map->dst->type == VPT_TYPE_ATTR) &&
(c->data.map->src->type == VPT_TYPE_LITERAL) &&
- !cast_vpt(c->data.map->src, c->data.map->dst->da)) {
- DICT_ATTR const *da = c->data.map->dst->da;
+ !radius_cast_tmpl(c->data.map->src, c->data.map->dst->vpt_da)) {
+ DICT_ATTR const *da = c->data.map->dst->vpt_da;
if ((da->vendor == 0) &&
((da->attr == PW_AUTH_TYPE) ||
}
}
- done_cond:
p += slen;
while (isspace((int) *p)) p++; /* skip spaces after RHS */
p++;
while (isspace((int) *p)) p++; /* skip spaces after closing brace */
- brace = false;
goto done;
}
done:
/*
- * Normalize it before returning it.
+ * Normalize the condition before returning.
+ *
+ * We collapse multiple levels of braces to one. Then
+ * convert maps to literals. Then literals to true/false
+ * statements. Then true/false ||/&& followed by other
+ * conditions to just conditions.
+ *
+ * Order is important. The more complex cases are
+ * converted to simpler ones, from the most complex cases
+ * to the simplest ones.
*/
/*
}
/*
- * Normalize negation. This doesn't really make any
- * difference, but it simplifies the run-time code in
- * evaluate.c
+ * Convert maps to literals. Convert one form of map to
+ * a standardized form. This doesn't make any
+ * theoretical difference, but it does mean that the
+ * run-time evaluation has fewer cases to check.
*/
- if (c->type == COND_TYPE_MAP) {
+ if (c->type == COND_TYPE_MAP) do {
/*
* !FOO !~ BAR --> FOO =~ BAR
*/
/*
* This next one catches "LDAP-Group != foo",
- * which doesn't really work, but this hack fixes it.
+ * which doesn't work as-is, but this hack fixes
+ * it.
*
* FOO != BAR --> !FOO == BAR
*/
c->data.map->op = T_OP_CMP_EQ;
}
+ /*
+ * FOO =* BAR --> FOO
+ * FOO !* BAR --> !FOO
+ */
+ if ((c->data.map->op == T_OP_CMP_TRUE) ||
+ (c->data.map->op == T_OP_CMP_FALSE)) {
+ value_pair_tmpl_t *vpt;
+
+ vpt = talloc_steal(c, c->data.map->dst);
+ c->data.map->dst = NULL;
+
+ /*
+ * Invert the negation bit.
+ */
+ if (c->data.map->op == T_OP_CMP_FALSE) {
+ c->negate = !c->negate;
+ }
+
+ TALLOC_FREE(c->data.map);
+
+ c->type = COND_TYPE_EXISTS;
+ c->data.vpt = vpt;
+ break; /* it's no longer a map */
+ }
+
+ /*
+ * Both are data (IP address, integer, etc.)
+ *
+ * We can do the evaluation here, so that it
+ * doesn't need to be done at run time
+ */
if ((c->data.map->dst->type == VPT_TYPE_DATA) &&
(c->data.map->src->type == VPT_TYPE_DATA)) {
int rcode;
rad_assert(c->cast != NULL);
rcode = radius_evaluate_map(NULL, 0, 0, c);
- talloc_free(c->data.map);
- c->data.map = NULL;
+ TALLOC_FREE(c->data.map);
c->cast = NULL;
- c->regex_i = false;
if (rcode) {
c->type = COND_TYPE_TRUE;
} else {
c->type = COND_TYPE_FALSE;
}
+
+ break; /* it's no longer a map */
+ }
+
+ /*
+ * Both are literal strings. They're not parsed
+ * as VPT_TYPE_DATA because there's no cast to an
+ * attribute.
+ *
+ * We can do the evaluation here, so that it
+ * doesn't need to be done at run time
+ */
+ if ((c->data.map->src->type == VPT_TYPE_LITERAL) &&
+ (c->data.map->dst->type == VPT_TYPE_LITERAL)) {
+ int rcode;
+
+ rad_assert(c->cast == NULL);
+
+ rcode = radius_evaluate_map(NULL, 0, 0, c);
+ if (rcode) {
+ c->type = COND_TYPE_TRUE;
+ } else {
+ c->type = COND_TYPE_FALSE;
+ }
+
+ /*
+ * Free map after using it above.
+ */
+ TALLOC_FREE(c->data.map);
+ break;
+ }
+
+ /*
+ * <ipaddr>"foo" CMP &Attribute-Name The cast is
+ * unnecessary, and we can re-write it so that
+ * the attribute reference is on the LHS.
+ */
+ if (c->cast &&
+ (c->data.map->src->type == VPT_TYPE_ATTR) &&
+ (c->data.map->dst->type != VPT_TYPE_ATTR)) {
+ value_pair_tmpl_t *tmp;
+
+ tmp = c->data.map->src;
+ c->data.map->src = c->data.map->dst;
+ c->data.map->dst = tmp;
+
+ c->cast = NULL;
+
+ switch (c->data.map->op) {
+ case T_OP_CMP_EQ:
+ /* do nothing */
+ break;
+
+ case T_OP_LE:
+ c->data.map->op = T_OP_GE;
+ break;
+
+ case T_OP_LT:
+ c->data.map->op = T_OP_GT;
+ break;
+
+ case T_OP_GE:
+ c->data.map->op = T_OP_LE;
+ break;
+
+ case T_OP_GT:
+ c->data.map->op = T_OP_LT;
+ break;
+
+ default:
+ return_0("Internal sanity check failed");
+ }
+
+ /*
+ * This must have been parsed into VPT_TYPE_DATA.
+ */
+ rad_assert(c->data.map->src->type != VPT_TYPE_LITERAL);
+ }
+
+ } while (0);
+
+ /*
+ * Existence checks. We short-circuit static strings,
+ * too.
+ */
+ if (c->type == COND_TYPE_EXISTS) {
+ switch (c->data.vpt->type) {
+ case VPT_TYPE_XLAT:
+ case VPT_TYPE_ATTR:
+ case VPT_TYPE_LIST:
+ case VPT_TYPE_EXEC:
+ break;
+
+ /*
+ * 'true' and 'false' are special strings
+ * which mean themselves.
+ *
+ * For integers, 0 is false, all other
+ * integers are true.
+ *
+ * For strings, '' and "" are false.
+ * 'foo' and "foo" are true.
+ *
+ * The str2tmpl function takes care of
+ * marking "%{foo}" as VPT_TYPE_XLAT, so
+ * the strings here are fixed at compile
+ * time.
+ *
+ * `exec` and "%{...}" are left alone.
+ *
+ * Bare words must be module return
+ * codes.
+ */
+ case VPT_TYPE_LITERAL:
+ if ((strcmp(c->data.vpt->name, "true") == 0) ||
+ (strcmp(c->data.vpt->name, "1") == 0)) {
+ c->type = COND_TYPE_TRUE;
+ TALLOC_FREE(c->data.vpt);
+
+ } else if ((strcmp(c->data.vpt->name, "false") == 0) ||
+ (strcmp(c->data.vpt->name, "0") == 0)) {
+ c->type = COND_TYPE_FALSE;
+ TALLOC_FREE(c->data.vpt);
+
+ } else if (!*c->data.vpt->name) {
+ c->type = COND_TYPE_FALSE;
+ TALLOC_FREE(c->data.vpt);
+
+ } else if ((lhs_type == T_SINGLE_QUOTED_STRING) ||
+ (lhs_type == T_DOUBLE_QUOTED_STRING)) {
+ c->type = COND_TYPE_TRUE;
+ TALLOC_FREE(c->data.vpt);
+
+ } else if (lhs_type == T_BARE_WORD) {
+ int rcode;
+ char const *q;
+
+ for (q = c->data.vpt->name;
+ *q != '\0';
+ q++) {
+ if (!isdigit((int) *q)) {
+ break;
+ }
+ }
+
+ /*
+ * It's all digits, and therefore
+ * 'true'.
+ */
+ if (!*q) {
+ c->type = COND_TYPE_TRUE;
+ TALLOC_FREE(c->data.vpt);
+ break;
+ }
+
+ rcode = fr_str2int(allowed_return_codes,
+ c->data.vpt->name, 0);
+ if (!rcode) {
+ return_0("Expected a module return code");
+ }
+ }
+
+ /*
+ * Else lhs_type==T_OP_INVALID, and this
+ * node was made by promoting a child
+ * which had already been normalized.
+ */
+ break;
+
+ case VPT_TYPE_DATA:
+ return_0("Cannot use data here");
+
+ default:
+ return_0("Internal sanity check failed");
}
}
+ /*
+ * !TRUE -> FALSE
+ */
if (c->type == COND_TYPE_TRUE) {
if (c->negate) {
c->negate = false;
}
}
+ /*
+ * !FALSE -> TRUE
+ */
if (c->type == COND_TYPE_FALSE) {
if (c->negate) {
c->negate = false;
extern bool check_config;
extern fr_cond_t *debug_condition;
-static int spawn_flag = 0;
-static int just_started = true;
-time_t fr_start_time;
+static bool spawn_flag = false;
+static bool just_started = true;
+time_t fr_start_time = (time_t)-1;
static fr_packet_list_t *pl = NULL;
static fr_event_list_t *el = NULL;
+fr_event_list_t *radius_event_list_corral(UNUSED event_corral_t hint) {
+ /* Currently we do not run a second event loop for modules. */
+ return el;
+}
+
static char const *action_codes[] = {
"INVALID",
"run",
};
#ifdef DEBUG_STATE_MACHINE
-#define TRACE_STATE_MACHINE if (debug_flag) printf("(%u) ********\tSTATE %s action %s live M%u C%u\t********\n", request->number, __FUNCTION__, action_codes[action], request->master_state, request->child_state)
+#define TRACE_STATE_MACHINE if (debug_flag) printf("(%u) ********\tSTATE %s action %s live M-%s C-%s\t********\n", request->number, __FUNCTION__, action_codes[action], master_state_names[request->master_state], child_state_names[request->child_state])
+
+static char const *master_state_names[REQUEST_MASTER_NUM_STATES] = {
+ "?",
+ "active",
+ "stop-processing",
+ "counted"
+};
+
+static char const *child_state_names[REQUEST_CHILD_NUM_STATES] = {
+ "?",
+ "queued",
+ "running",
+ "proxied",
+ "reject-delay",
+ "cleanup-delay",
+ "done"
+};
+
#else
#define TRACE_STATE_MACHINE {}
#endif
* Declare a state in the state machine.
*
*/
-#define STATE_MACHINE_DECL(_x) static void _x(REQUEST *request, int action)
+#define STATE_MACHINE_DECL(_x) static void CC_HINT(nonnull) _x(REQUEST *request, int action)
#define STATE_MACHINE_TIMER(_x) request->timer_action = _x; \
fr_event_insert(el, request_timer, request, \
* - Y: Reply is ready. Rejects MAY be delayed here. All other
* replies are sent immediately.
*
- * - J: Reject is sent "reject_delay" after the reply is ready.
+ * - J: Reject is sent "response_delay" after the reply is ready.
*
* - C: For Access-Requests, After "cleanup_delay", the request is
* deleted. Accounting-Request packets go directly from Y to C.
#ifdef HAVE_PTHREAD_H
#ifdef WITH_PROXY
-static pthread_mutex_t proxy_mutex;
-static rad_listen_t *proxy_listener_list = NULL;
-static int proxy_no_new_sockets = false;
+static pthread_mutex_t proxy_mutex;
+static bool proxy_no_new_sockets = false;
#endif
#define PTHREAD_MUTEX_LOCK if (spawn_flag) pthread_mutex_lock
#define PTHREAD_MUTEX_UNLOCK if (spawn_flag) pthread_mutex_unlock
static pthread_t NO_SUCH_CHILD_PID;
+#define NO_CHILD_THREAD request->child_pid = NO_SUCH_CHILD_PID
+
#else
/*
* This is easier than ifdef's throughout the code.
*/
#define PTHREAD_MUTEX_LOCK(_x)
#define PTHREAD_MUTEX_UNLOCK(_x)
+#define NO_CHILD_THREAD
+#endif
+
+#if defined(HAVE_PTHREAD_H) && !defined (NDEBUG)
+static bool we_are_master(void)
+{
+ if (spawn_flag &&
+ (pthread_equal(pthread_self(), NO_SUCH_CHILD_PID) == 0)) {
+ return false;
+ }
+
+ return true;
+}
+#define ASSERT_MASTER if (!we_are_master()) rad_panic("We are not master")
+
+#else
+#define we_are_master(_x) (1)
+#define ASSERT_MASTER
#endif
+static int event_new_fd(rad_listen_t *this);
+
/*
* We need mutexes around the event FD list *only* in certain
* cases.
*/
#if defined (HAVE_PTHREAD_H) && (defined(WITH_PROXY) || defined(WITH_TCP))
+static rad_listen_t *new_listeners = NULL;
+
static pthread_mutex_t fd_mutex;
#define FD_MUTEX_LOCK if (spawn_flag) pthread_mutex_lock
#define FD_MUTEX_UNLOCK if (spawn_flag) pthread_mutex_unlock
+
+void radius_update_listener(rad_listen_t *this)
+{
+ /*
+ * Just do it ourselves.
+ */
+ if (we_are_master()) {
+ event_new_fd(this);
+ return;
+ }
+
+ FD_MUTEX_LOCK(&fd_mutex);
+
+ /*
+ * If it's already in the list, don't add it again.
+ */
+ if (this->next) {
+ FD_MUTEX_UNLOCK(&fd_mutex);
+ return;
+ }
+
+ /*
+ * Otherwise, add it to the list
+ */
+ this->next = new_listeners;
+ new_listeners = this;
+ FD_MUTEX_UNLOCK(&fd_mutex);
+ radius_signal_self(RADIUS_SIGNAL_SELF_NEW_FD);
+}
#else
+void radius_update_listener(rad_listen_t *this)
+{
+ /*
+ * No threads. Just insert it.
+ */
+ event_new_fd(this);
+}
/*
* This is easier than ifdef's throughout the code.
*/
#define FD_MUTEX_UNLOCK(_x)
#endif
-static int request_num_counter = 0;
+static int request_num_counter = 1;
#ifdef WITH_PROXY
static int request_will_proxy(REQUEST *request);
static int request_proxy(REQUEST *request, int retransmit);
STATE_MACHINE_DECL(proxy_wait_for_reply);
+STATE_MACHINE_DECL(proxy_no_reply);
STATE_MACHINE_DECL(proxy_running);
-static int process_proxy_reply(REQUEST *request);
+static int process_proxy_reply(REQUEST *request, RADIUS_PACKET *reply);
static void remove_from_proxy_hash(REQUEST *request);
static void remove_from_proxy_hash_nl(REQUEST *request, bool yank);
static int insert_into_proxy_hash(REQUEST *request);
RADCLIENT *client, RAD_REQUEST_FUNP fun);
STATE_MACHINE_DECL(request_common);
-
-#if defined(HAVE_PTHREAD_H) && !defined (NDEBUG)
-static int we_are_master(void)
-{
- if (spawn_flag &&
- (pthread_equal(pthread_self(), NO_SUCH_CHILD_PID) == 0)) {
- return 0;
- }
-
- return 1;
-}
-#define ASSERT_MASTER if (!we_are_master()) rad_panic("We are not master")
-
-#else
-#define we_are_master(_x) (1)
-#define ASSERT_MASTER
-#endif
-
-STATE_MACHINE_DECL(request_reject_delay);
+STATE_MACHINE_DECL(request_response_delay);
STATE_MACHINE_DECL(request_cleanup_delay);
STATE_MACHINE_DECL(request_running);
#ifdef WITH_COA
-static void request_coa_timer(REQUEST *request);
static void request_coa_originate(REQUEST *request);
-STATE_MACHINE_DECL(request_coa_process);
+STATE_MACHINE_DECL(coa_running);
+STATE_MACHINE_DECL(coa_wait_for_reply);
+STATE_MACHINE_DECL(coa_no_reply);
static void request_coa_separate(REQUEST *coa);
#endif
/*
* In daemon mode, AND this request has debug flags set.
*/
-#define DEBUG_PACKET if (!debug_flag && request->options && request->radlog) debug_packet
+#define DEBUG_PACKET if (!debug_flag && request->log.lvl && request->log.func) debug_packet
static void debug_packet(REQUEST *request, RADIUS_PACKET *packet, int direction)
{
char buffer[1024];
char const *received, *from;
fr_ipaddr_t const *ip;
- int port;
+ uint16_t port;
if (!packet) return;
- rad_assert(request->radlog != NULL);
+ rad_assert(request->log.func != NULL);
if (direction == 0) {
received = "Received";
*
* This really belongs in a utility library
*/
- if ((packet->code > 0) && (packet->code < FR_MAX_PACKET_CODE)) {
- RDEBUG("%s %s packet %s host %s port %d, id=%d, length=%d",
+ if (is_radius_code(packet->code)) {
+ RDEBUG("%s %s packet %s host %s port %i, id=%i, length=%zu",
received, fr_packet_codes[packet->code], from,
inet_ntop(ip->af, &ip->ipaddr, buffer, sizeof(buffer)),
port, packet->id, packet->data_len);
} else {
- RDEBUG("%s packet %s host %s port %d code=%d, id=%d, length=%d",
+ RDEBUG("%s packet %s host %s port %d code=%d, id=%d, length=%zu",
received, from,
inet_ntop(ip->af, &ip->ipaddr, buffer, sizeof(buffer)),
port,
packet->code, packet->id, packet->data_len);
}
- for (vp = paircursor(&cursor, &packet->vps);
+ for (vp = fr_cursor_init(&cursor, &packet->vps);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
vp_prints(buffer, sizeof(buffer), vp);
RDEBUG("\t%s", buffer);
}
*
***********************************************************************/
+static struct timeval *request_response_window(REQUEST *request)
+{
+ /*
+ * The client hasn't set the response window. Return
+ * either the home server one, if set, or the global one.
+ */
+ if (!timerisset(&request->client->response_window)) {
+ return &request->home_server->response_window;
+ }
+
+ if (timercmp(&request->client->response_window,
+ &request->home_server->response_window, <)) {
+ return &request->client->response_window;
+ }
+
+ return &request->home_server->response_window;
+}
+
/*
* Callback for ALL timer events related to the request.
*/
request->process(request, action);
}
-#define USEC (1000000)
-
/*
* Only ever called from the master thread.
*/
STATE_MACHINE_DECL(request_done)
{
struct timeval now, when;
+#ifdef WITH_PROXY
+ char buffer[128];
+#endif
TRACE_STATE_MACHINE;
*/
if (!we_are_master()) {
request->child_state = REQUEST_DONE;
- request->child_pid = NO_SUCH_CHILD_PID;;
+ NO_CHILD_THREAD;
return;
}
#endif
/*
* Move the CoA request to its own handler.
*/
- if (request->coa) request_coa_separate(request->coa);
-
- /*
- * If we're the CoA request, make the parent forget about
- * us.
- */
- if (request->parent && (request->parent->coa == request)) {
- request->parent->coa = NULL;
+ if (request->coa) {
+ request_coa_separate(request->coa);
+ } else if (request->parent && (request->parent->coa == request)) {
+ request_coa_separate(request);
}
#endif
if (request->reply->code != 0) {
request->listener->send(request->listener, request);
return;
+ } else {
+ RDEBUG("No reply. Ignoring retransmit");
}
break;
}
#endif
#ifdef DEBUG_STATE_MACHINE
- if (debug_flag) printf("(%u) ********\tSTATE %s C%u -> C%u\t********\n", request->number, __FUNCTION__, request->child_state, REQUEST_DONE);
+ if (debug_flag) printf("(%u) ********\tSTATE %s C-%s -> C-%s\t********\n",
+ request->number, __FUNCTION__,
+ child_state_names[request->child_state],
+ child_state_names[REQUEST_DONE]);
#endif
request->child_state = REQUEST_DONE;
break;
* packets from the home server.
*/
case FR_ACTION_PROXY_REPLY:
- request_common(request, action);
- break;
+ RDEBUG2("Reply from home server %s port %d - ID: %d arrived too late. Try increasing 'retry_delay' or 'max_request_time'",
+ inet_ntop(request->proxy->src_ipaddr.af,
+ &request->proxy->src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port, request->proxy->id);
+ return;
#endif
default:
rad_assert(0 == 1);
}
request->in_request_hash = false;
-
- /*
- * @todo: do final states for TCP sockets, too?
- */
- request_stats_final(request);
-
-#ifdef WITH_TCP
- request->listener->count--;
-#endif
}
#ifdef WITH_PROXY
when = request->proxy->timestamp;
#ifdef WITH_COA
- if (((request->proxy->code == PW_COA_REQUEST) ||
- (request->proxy->code == PW_DISCONNECT_REQUEST)) &&
+ if (((request->proxy->code == PW_CODE_COA_REQUEST) ||
+ (request->proxy->code == PW_CODE_DISCONNECT_REQUEST)) &&
(request->packet->code != request->proxy->code)) {
when.tv_sec += request->home_server->coa_mrd;
} else
#endif
- when.tv_sec += request->home_server->response_window;
+ timeradd(&when, request_response_window(request), &when);
/*
* We haven't received all responses, AND there's still
rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
#endif
+ /*
+ * @todo: do final states for TCP sockets, too?
+ */
+ request_stats_final(request);
+#ifdef WITH_TCP
+ if (request->listener) request->listener->count--;
+#endif
+
if (request->packet) {
RDEBUG2("Cleaning up request packet ID %u with timestamp +%d",
request->packet->id,
{
struct timeval now, when;
- if (request->packet->code == PW_ACCOUNTING_REQUEST) goto done;
+ if (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) goto done;
+
if (!request->root->cleanup_delay) goto done;
if (pnow) {
if (request->coa) request_coa_separate(request->coa);
/*
- * Check request stuff ONLY if we're running the request.
+ * If we're the request, OR it isn't originating a CoA
+ * request, check more things.
*/
if (!request->proxy || (request->packet->code == request->proxy->code))
#endif
* there is no point in continuing.
*/
if (request->listener->status != RAD_LISTEN_STATUS_KNOWN) {
- WDEBUG("Socket was closed while processing request %u: Stopping it.", request->number);
-#ifdef WITH_ACCOUNTING
- goto done;
-#else
+ if ((request->master_state == REQUEST_ACTIVE) &&
+ (request->child_state < REQUEST_RESPONSE_DELAY)) {
+ WARN("Socket was closed while processing request %u: Stopping it.", request->number);
+ request->master_state = REQUEST_STOP_PROCESSING;
+ }
+ }
+ }
+
+ gettimeofday(&now, NULL);
+
+ /*
+ * The request was forcibly stopped.
+ */
+ if (request->master_state == REQUEST_STOP_PROCESSING) {
+ switch (request->child_state) {
+ case REQUEST_QUEUED:
+ case REQUEST_RUNNING:
+#ifdef HAVE_PTHREAD_H
+ rad_assert(spawn_flag == true);
+#endif
+
+ delay:
+ /*
+ * Sleep for some more. We HOPE that the
+ * child will become responsive at some
+ * point in the future.
+ */
+ when = now;
+ tv_add(&when, request->delay);
+ request->delay += request->delay >> 1;
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+ return;
+
+ /*
+ * These should all be managed by the master thread
+ */
+#ifdef WITH_PROXY
+ case REQUEST_PROXIED:
+#endif
+ case REQUEST_RESPONSE_DELAY:
+ case REQUEST_CLEANUP_DELAY:
+ case REQUEST_DONE:
done:
request_done(request, FR_ACTION_DONE);
return;
-#endif
-
}
}
- gettimeofday(&now, NULL);
+ rad_assert(request->master_state == REQUEST_ACTIVE);
/*
- * A child thread is still working on the request,
- * OR it was proxied, and there was no response,
- * OR it was sitting in the queue for too long.
+ * It's still supposed to be running.
*/
- if ((request->child_state != REQUEST_DONE) &&
- (request->master_state != REQUEST_STOP_PROCESSING)) {
+ switch (request->child_state) {
+ case REQUEST_QUEUED:
+ case REQUEST_RUNNING:
+#ifdef WITH_PROXY
+ case REQUEST_PROXIED:
+#endif
when = request->packet->timestamp;
when.tv_sec += request->root->max_request_time;
if (spawn_flag &&
(pthread_equal(request->child_pid, NO_SUCH_CHILD_PID) == 0)) {
ERROR("Unresponsive child for request %u, in component %s module %s",
- request->number,
- request->component ? request->component : "<core>",
- request->module ? request->module : "<core>");
+ request->number,
+ request->component ? request->component : "<core>",
+ request->module ? request->module : "<core>");
exec_trigger(request, NULL, "server.thread.unresponsive", true);
}
#endif
+ request->master_state = REQUEST_STOP_PROCESSING;
+ }
+
+#ifdef WITH_PROXY
+ /*
+ * We should wait for the proxy reply.
+ */
+ if (request->child_state == REQUEST_PROXIED) {
+ rad_assert(request->proxy != NULL);
+#ifdef WITH_COA
/*
- * Tell the request to stop it.
+ * Ugh.
*/
- goto done;
- } /* else we're not at max_request_time */
-
-#ifdef WITH_PROXY
- if ((request->master_state != REQUEST_STOP_PROCESSING) &&
- request->proxy &&
- (request->process == request_running)) {
-#ifdef DEBUG_STATE_MACHINE
- if (debug_flag) printf("(%u) ********\tNEXT-STATE %s -> %s\n", request->number, __FUNCTION__, "request_proxied");
+ if (request->packet->code != request->proxy->code) {
+ if (request->proxy_reply) {
+ request->process = coa_running;
+ } else {
+ request->process = coa_wait_for_reply;
+ }
+ goto delay;
+ }
#endif
- request->process = proxy_wait_for_reply;
+ if (request->proxy_reply) {
+ request->process = proxy_running;
+ } else {
+ request->process = proxy_wait_for_reply;
+ }
}
#endif
/*
- * Wake up again in the future, to check for
- * more things to do.
+ * If the request has been told to die, we wait.
+ * Otherwise, we wait for the child thread to
+ * finish it's work.
*/
- when = now;
- tv_add(&when, request->delay);
- request->delay += request->delay >> 1;
+ goto delay;
- STATE_MACHINE_TIMER(FR_ACTION_TIMER);
- return;
- }
+ case REQUEST_RESPONSE_DELAY:
+ rad_assert(request->response_delay > 0);
+#ifdef WITH_COA
+ rad_assert(!request->proxy || (request->packet->code == request->proxy->code));
+#endif
-#ifdef WITH_ACCOUNTING
- if (request->reply->code == PW_ACCOUNTING_RESPONSE) {
- done:
- request_done(request, FR_ACTION_DONE);
- return;
- }
+ request->process = request_response_delay;
+
+ when = request->reply->timestamp;
+
+ tv_add(&when, request->response_delay * USEC);
+
+ if (timercmp(&when, &now, >)) {
+#ifdef DEBUG_STATE_MACHINE
+ if (debug_flag) printf("(%u) ********\tNEXT-STATE %s -> %s\n", request->number, __FUNCTION__, "request_response_delay");
#endif
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+ return;
+ } /* else it's time to send the reject */
+
+ RDEBUG2("Sending delayed response");
+ DEBUG_PACKET(request, request->reply, 1);
+ request->listener->send(request->listener, request);
+ request->child_state = REQUEST_CLEANUP_DELAY;
+ /* FALL-THROUGH */
+
+ case REQUEST_CLEANUP_DELAY:
+ rad_assert(request->root->cleanup_delay > 0);
#ifdef WITH_COA
- if (!request->proxy || (request->packet->code == request->proxy->code))
+ rad_assert(!request->proxy || (request->packet->code == request->proxy->code));
#endif
- if ((request->reply->code == PW_AUTHENTICATION_REJECT) &&
- (request->root->reject_delay)) {
- rad_assert(request->reply->timestamp.tv_sec != 0);
+ request->process = request_cleanup_delay;
when = request->reply->timestamp;
- when.tv_sec += request->root->reject_delay;
+ when.tv_sec += request->root->cleanup_delay;
- /*
- * Set timer for when we need to send it.
- */
if (timercmp(&when, &now, >)) {
#ifdef DEBUG_STATE_MACHINE
- if (debug_flag) printf("(%u) ********\tNEXT-STATE %s -> %s\n", request->number, __FUNCTION__, "request_reject_delay");
+ if (debug_flag) printf("(%u) ********\tNEXT-STATE %s -> %s\n", request->number, __FUNCTION__, "request_cleanup_delay");
#endif
- request->process = request_reject_delay;
-
STATE_MACHINE_TIMER(FR_ACTION_TIMER);
return;
- }
-
- if (request->process == request_reject_delay) {
- /*
- * Assume we're at (or near) the reject
- * delay time.
- */
- request->reply->timestamp = now;
+ } /* else it's time to clean up */
+ /* FALL-THROUGH */
- RDEBUG2("Sending delayed reject");
- DEBUG_PACKET(request, request->reply, 1);
- request->process = request_cleanup_delay;
- request->listener->send(request->listener, request);
- }
+ case REQUEST_DONE:
+ goto done;
}
- /*
- * The cleanup_delay is zero for accounting packets, and
- * enforced for all other packets. We do the
- * cleanup_delay even if we don't respond to the NAS, so
- * that any retransmit is *not* processed as a new packet.
- */
- request_cleanup_delay_init(request, &now);
- return;
}
static void request_queue_or_run(UNUSED REQUEST *request,
fr_request_process_t process)
{
- struct timeval when;
#ifdef DEBUG_STATE_MACHINE
int action = FR_ACTION_TIMER;
#endif
TRACE_STATE_MACHINE;
- ASSERT_MASTER;
-
- /*
- * (re) set the initial delay.
- */
- request->delay = USEC / 3;
- gettimeofday(&when, NULL);
- tv_add(&when, request->delay);
- request->delay += request->delay >> 1;
-
- STATE_MACHINE_TIMER(FR_ACTION_TIMER);
/*
* Do this here so that fewer other functions need to do
*/
if (request->master_state == REQUEST_STOP_PROCESSING) {
#ifdef DEBUG_STATE_MACHINE
- if (debug_flag) printf("(%u) ********\tSTATE %s C%u -> C%u\t********\n", request->number, __FUNCTION__, request->child_state, REQUEST_DONE);
+ if (debug_flag) printf("(%u) ********\tSTATE %s M-%s causes C-%s-> C-%s\t********\n",
+ request->number, __FUNCTION__,
+ master_state_names[request->master_state],
+ child_state_names[request->child_state],
+ child_state_names[REQUEST_DONE]);
#endif
request_done(request, FR_ACTION_DONE);
return;
request->process = process;
-#ifdef HAVE_PTHREAD_H
- if (spawn_flag) {
- /*
- * A child thread will eventually pick it up.
- */
- if (request_enqueue(request)) return;
+ if (we_are_master()) {
+ struct timeval when;
/*
- * Otherwise we're not going to do anything with
- * it...
+ * (re) set the initial delay.
*/
- request_done(request, FR_ACTION_DONE);
- return;
+ request->delay = (main_config.init_delay.tv_sec * USEC) + main_config.init_delay.tv_usec;
+ if (request->delay > USEC) request->delay = USEC;
+ gettimeofday(&when, NULL);
+ tv_add(&when, request->delay);
+ request->delay += request->delay >> 1;
- } else
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+
+#ifdef HAVE_PTHREAD_H
+ if (spawn_flag) {
+ /*
+ * A child thread will eventually pick it up.
+ */
+ if (request_enqueue(request)) return;
+
+ /*
+ * Otherwise we're not going to do anything with
+ * it...
+ */
+ request_done(request, FR_ACTION_DONE);
+ return;
+ }
#endif
- {
- request->process(request, FR_ACTION_RUN);
+ }
+
+ request->child_state = REQUEST_RUNNING;
+ request->process(request, FR_ACTION_RUN);
#ifdef WNOHANG
- /*
- * Requests that care about child process exit
- * codes have already either called
- * rad_waitpid(), or they've given up.
- */
- while (waitpid(-1, NULL, WNOHANG) > 0);
+ /*
+ * Requests that care about child process exit
+ * codes have already either called
+ * rad_waitpid(), or they've given up.
+ */
+ while (waitpid(-1, NULL, WNOHANG) > 0);
#endif
- }
}
STATE_MACHINE_DECL(request_common)
#endif
TRACE_STATE_MACHINE;
+ ASSERT_MASTER;
+
+ /*
+ * Bail out as early as possible.
+ */
+ if (request->master_state == REQUEST_STOP_PROCESSING) {
+ request_done(request, FR_ACTION_DONE);
+ return;
+ }
switch (action) {
case FR_ACTION_DUP:
#ifdef WITH_PROXY
- if ((request->master_state != REQUEST_STOP_PROCESSING) &&
- request->proxy && !request->proxy_reply) {
- /*
- * TODO: deal with this in a better way?
- */
+ /*
+ * We're still waiting for a proxy reply.
+ */
+ if (request->child_state == REQUEST_PROXIED) {
+ request->process = proxy_wait_for_reply;
proxy_wait_for_reply(request, action);
return;
}
#endif
- ERROR("(%u) Discarding duplicate request from "
- "client %s port %d - ID: %u due to unfinished request",
- request->number, request->client->shortname,
- request->packet->src_port,request->packet->id);
+
+ ERROR("(%u) Ignoring duplicate packet from "
+ "client %s port %d - ID: %u due to unfinished request "
+ "in component %s module %s",
+ request->number, request->client->shortname,
+ request->packet->src_port,request->packet->id,
+ request->component, request->module);
break;
case FR_ACTION_CONFLICTING:
#ifdef WITH_PROXY
case FR_ACTION_PROXY_REPLY:
- DEBUG2("Reply from home server %s port %d - ID: %d arrived too late for request %u. Try increasing 'retry_delay' or 'max_request_time'",
- inet_ntop(request->proxy->src_ipaddr.af,
- &request->proxy->src_ipaddr.ipaddr,
+ RDEBUG2("Reply from home server %s port %d - ID: %d arrived too late. Try increasing 'retry_delay' or 'max_request_time'",
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
buffer, sizeof(buffer)),
- request->proxy->dst_port, request->proxy->id,
- request->number);
+ request->proxy->dst_port, request->proxy->id);
return;
#endif
if (request->reply->code != 0) {
request->listener->send(request->listener, request);
} else {
- RDEBUG("No reply. Ignoring retransmit.");
+ RDEBUG("No reply. Ignoring retransmit");
}
/*
STATE_MACHINE_TIMER(FR_ACTION_TIMER);
return;
+ case FR_ACTION_CONFLICTING:
+ request_done(request, FR_ACTION_DONE);
+ break;
+
#ifdef WITH_PROXY
case FR_ACTION_PROXY_REPLY:
#endif
- case FR_ACTION_CONFLICTING:
case FR_ACTION_TIMER:
request_common(request, action);
return;
}
}
-STATE_MACHINE_DECL(request_reject_delay)
+STATE_MACHINE_DECL(request_response_delay)
{
TRACE_STATE_MACHINE;
ASSERT_MASTER;
switch (action) {
case FR_ACTION_DUP:
ERROR("(%u) Discarding duplicate request from "
- "client %s port %d - ID: %u due to delayed reject",
+ "client %s port %d - ID: %u due to delayed response",
request->number, request->client->shortname,
request->packet->src_port,request->packet->id);
return;
}
-static int request_pre_handler(REQUEST *request, UNUSED int action)
+static int CC_HINT(nonnull) request_pre_handler(REQUEST *request, UNUSED int action)
{
TRACE_STATE_MACHINE;
return 1;
}
-#ifdef WITH_PROXY
- /*
- * Put the decoded packet into it's proper place.
- */
- if (request->proxy_reply != NULL) {
- /*
- * There may be a proxy reply, but it may be too late.
- */
- if (!request->proxy_listener) return 0;
-
- rcode = request->proxy_listener->decode(request->proxy_listener, request);
- DEBUG_PACKET(request, request->proxy_reply, 0);
-
- /*
- * Pro-actively remove it from the proxy hash.
- * This is later than in 2.1.x, but it means that
- * the replies are authenticated before being
- * removed from the hash.
- */
- if ((rcode == 0) &&
- (request->num_proxied_requests <= request->num_proxied_responses)) {
- remove_from_proxy_hash(request);
- }
-
- } else
-#endif
- if (request->packet->vps == NULL) {
- rcode = request->listener->decode(request->listener, request);
+ if (!request->packet->vps) { /* FIXME: check for correct state */
+ rcode = request->listener->decode(request->listener, request);
#ifdef WITH_UNLANG
if (debug_condition) {
* Ignore parse errors.
*/
if (radius_evaluate_cond(request, RLM_MODULE_OK, 0, debug_condition)) {
- request->options = 2;
- request->radlog = radlog_request;
+ request->log.lvl = L_DBG_LVL_2;
+ request->log.func = vradlog_request;
}
}
#endif
request->username = pairfind(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
}
-#ifdef WITH_PROXY
- if (action == FR_ACTION_PROXY_REPLY) {
- return process_proxy_reply(request);
- }
-#endif
-
return 1;
}
(void) action; /* -Wunused */
- if (request->master_state == REQUEST_STOP_PROCESSING) return;
+ if (request->master_state == REQUEST_STOP_PROCESSING) {
+ NO_CHILD_THREAD;
+ return;
+ }
/*
* Don't send replies if there are none to send.
*/
}
#else
+ NO_CHILD_THREAD;
return;
#endif
}
/*
* Catch Auth-Type := Reject BEFORE proxying the packet.
*/
- else if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
+ else if (request->packet->code == PW_CODE_AUTHENTICATION_REQUEST) {
if (request->reply->code == 0) {
vp = pairfind(request->config_items, PW_AUTH_TYPE, 0, TAG_ANY);
- if (!vp || (vp->vp_integer != PW_AUTHENTICATION_REJECT)) {
+ if (!vp || (vp->vp_integer != PW_CODE_AUTHENTICATION_REJECT)) {
RDEBUG2("There was no response configured: "
"rejecting request");
}
- request->reply->code = PW_AUTHENTICATION_REJECT;
+ request->reply->code = PW_CODE_AUTHENTICATION_REJECT;
}
}
if (vp) pairadd(&request->reply->vps, vp);
switch (request->reply->code) {
- case PW_AUTHENTICATION_ACK:
+ case PW_CODE_AUTHENTICATION_ACK:
rad_postauth(request);
break;
- case PW_ACCESS_CHALLENGE:
+ case PW_CODE_ACCESS_CHALLENGE:
pairdelete(&request->config_items, PW_POST_AUTH_TYPE, 0,
TAG_ANY);
vp = pairmake_config("Post-Auth-Type", "Challenge", T_OP_SET);
* We do this separately so ACK and challenge can change the code
* to reject if a module returns reject.
*/
- if (request->reply->code == PW_AUTHENTICATION_REJECT) {
+ if (request->reply->code == PW_CODE_AUTHENTICATION_REJECT) {
pairdelete(&request->config_items, PW_POST_AUTH_TYPE, 0, TAG_ANY);
vp = pairmake_config("Post-Auth-Type", "Reject", T_OP_SET);
if (vp) rad_postauth(request);
}
/*
- * Send the reply here.
- */
- if ((request->reply->code != PW_AUTHENTICATION_REJECT) ||
- (request->root->reject_delay == 0)) {
- DEBUG_PACKET(request, request->reply, 1);
- request->listener->send(request->listener,
- request);
- pairfree(&request->reply->vps);
- }
-
- /*
* Clean up. These are no longer needed.
*/
pairfree(&request->config_items);
}
#endif
- RDEBUG2("Finished request %u.", request->number);
+ gettimeofday(&request->reply->timestamp, NULL);
+
+ /*
+ * Ignore all "do not respond" packets.
+ */
+ if (!request->reply->code) {
+ RDEBUG("Not sending reply");
+ goto done;
+ }
+
+ /*
+ * See if we need to delay an Access-Reject packet.
+ */
+ if ((request->reply->code == PW_CODE_AUTHENTICATION_REJECT) &&
+ (request->root->reject_delay > 0)) {
+ request->response_delay = request->root->reject_delay;
+
+#ifdef WITH_PROXY
+ /*
+ * If we timed out a proxy packet, don't delay
+ * the reject any more.
+ */
+ if (request->proxy && !request->proxy_reply) {
+ request->response_delay = 0;
+ }
+#endif
+
+ }
+
+ /*
+ * Send the reply.
+ */
+ if (!request->response_delay) {
+ DEBUG_PACKET(request, request->reply, 1);
+ request->listener->send(request->listener,
+ request);
+
+ done:
+ pairfree(&request->reply->vps);
+
+ RDEBUG2("Finished request");
+#ifdef WITH_ACCOUNTING
+ if (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) {
+ NO_CHILD_THREAD;
+ request->child_state = REQUEST_DONE;
+ } else
+#endif
+
+ if (request->root->cleanup_delay == 0) {
+ NO_CHILD_THREAD;
+ request->child_state = REQUEST_DONE;
+ } else {
+ NO_CHILD_THREAD;
+ request->child_state = REQUEST_CLEANUP_DELAY;
+ }
+ } else {
+ RDEBUG2("Delaying response for %d seconds",
+ request->response_delay);
+ NO_CHILD_THREAD;
+ request->child_state = REQUEST_RESPONSE_DELAY;
+ }
}
STATE_MACHINE_DECL(request_running)
TRACE_STATE_MACHINE;
switch (action) {
+ case FR_ACTION_TIMER:
+ request_process_timer(request);
+ break;
+
case FR_ACTION_CONFLICTING:
case FR_ACTION_DUP:
- case FR_ACTION_TIMER:
request_common(request, action);
return;
#ifdef WITH_PROXY
- case FR_ACTION_PROXY_REPLY:
-#ifdef HAVE_PTHREAD_H
/*
- * Catch the case of a proxy reply when called
- * from the main worker thread.
+ * This can happen due to a race condition where
+ * we send a proxied request, and immediately get
+ * another reply, before the timer has a chance
+ * to update the various states.
*/
- if (we_are_master() &&
- (request->process != proxy_running)) {
- request_queue_or_run(request, proxy_running);
- return;
- }
- /* FALL-THROUGH */
-#endif
+ case FR_ACTION_PROXY_REPLY:
+ request->child_state = REQUEST_RUNNING;
+ request->process = proxy_running;
+ request->process(request, FR_ACTION_RUN);
+ break;
#endif
case FR_ACTION_RUN:
- if (!request_pre_handler(request, action)) goto done;
+ if (!request_pre_handler(request, action)) {
+#ifdef DEBUG_STATE_MACHINE
+ if (debug_flag) printf("(%u) ********\tSTATE %s failed in pre-handler C-%s -> C-%s\t********\n",
+ request->number, __FUNCTION__,
+ child_state_names[request->child_state],
+ child_state_names[REQUEST_DONE]);
+#endif
+
+ NO_CHILD_THREAD;
+ request->child_state = REQUEST_DONE;
+ break;
+ }
rad_assert(request->handle != NULL);
request->handle(request);
finished:
#endif
request_finish(request, action);
-
- done:
- /*
- * Get the time of the reply, which is
- * when we're done.
- */
- gettimeofday(&request->reply->timestamp, NULL);
-
-#ifdef DEBUG_STATE_MACHINE
- if (debug_flag) printf("(%u) ********\tSTATE %s C%u -> C%u\t********\n", request->number, __FUNCTION__, request->child_state, REQUEST_DONE);
-#endif
-
-#ifdef HAVE_PTHREAD_H
- request->child_pid = NO_SUCH_CHILD_PID;
-#endif
- request->child_state = REQUEST_DONE;
}
break;
int request_receive(rad_listen_t *listener, RADIUS_PACKET *packet,
RADCLIENT *client, RAD_REQUEST_FUNP fun)
{
- int count;
+ uint32_t count;
RADIUS_PACKET **packet_p;
REQUEST *request = NULL;
struct timeval now;
(memcmp(request->packet->vector, packet->vector,
sizeof(packet->vector)) == 0)) {
+ /*
+ * If the request is running, it'
+ */
+ if (request->child_state != REQUEST_DONE) {
+ request->process(request, FR_ACTION_DUP);
+
#ifdef WITH_STATS
- switch (packet->code) {
- case PW_AUTHENTICATION_REQUEST:
- FR_STATS_INC(auth, total_dup_requests);
- break;
+ switch (packet->code) {
+ case PW_CODE_AUTHENTICATION_REQUEST:
+ FR_STATS_INC(auth, total_dup_requests);
+ break;
#ifdef WITH_ACCOUNTING
- case PW_ACCOUNTING_REQUEST:
- FR_STATS_INC(acct, total_dup_requests);
- break;
+ case PW_CODE_ACCOUNTING_REQUEST:
+ FR_STATS_INC(acct, total_dup_requests);
+ break;
#endif
#ifdef WITH_COA
- case PW_COA_REQUEST:
- FR_STATS_INC(coa, total_dup_requests);
- break;
+ case PW_CODE_COA_REQUEST:
+ FR_STATS_INC(coa, total_dup_requests);
+ break;
- case PW_DISCONNECT_REQUEST:
- FR_STATS_INC(dsc, total_dup_requests);
- break;
+ case PW_CODE_DISCONNECT_REQUEST:
+ FR_STATS_INC(dsc, total_dup_requests);
+ break;
#endif
- default:
- break;
- }
+ default:
+ break;
+ }
#endif /* WITH_STATS */
+ return 0; /* duplicate of live request */
+ }
+#ifdef HAVE_PTHREAD_H
+ /*
+ * There should no longer be a child
+ * thread associated with this request.
+ */
+ rad_assert(pthread_equal(request->child_pid, NO_SUCH_CHILD_PID) != 0);
+#endif
- request->process(request, FR_ACTION_DUP);
- return 0;
- }
+ /*
+ * Clean up the old request, and allow
+ * the new one to continue.
+ */
+ request_done(request, FR_ACTION_DONE);
+ request = NULL;
- /*
- * Say we're ignoring the old one, and continue
- * to process the new one.
- */
- request->process(request, FR_ACTION_CONFLICTING);
- request = NULL;
+ } else {
+ /*
+ * Say we're ignoring the old one, and continue
+ * to process the new one.
+ */
+ request->process(request, FR_ACTION_CONFLICTING);
+ request = NULL;
+ }
}
/*
* Quench maximum number of outstanding requests.
*/
- if (mainconfig.max_requests &&
- ((count = fr_packet_list_num_elements(pl)) > mainconfig.max_requests)) {
- ERROR("Dropping request (%d is too many): from client %s port %d - ID: %d", count,
- client->shortname,
- packet->src_port, packet->id);
- WARN("Please check the configuration file.\n"
- "\tThe value for 'max_requests' is probably set too low.\n");
+ if (main_config.max_requests &&
+ ((count = fr_packet_list_num_elements(pl)) > main_config.max_requests)) {
+ RATE_LIMIT(ERROR("Dropping request (%d is too many): from client %s port %d - ID: %d", count,
+ client->shortname,
+ packet->src_port, packet->id);
+ WARN("Please check the configuration file.\n"
+ "\tThe value for 'max_requests' is probably set too low.\n"));
exec_trigger(NULL, NULL, "server.max_requests", true);
return 0;
* Rate-limit the incoming packets
*/
if (sock && sock->max_rate) {
- int pps;
-
- pps = rad_pps(&sock->rate_pps_old, &sock->rate_pps_now,
- &sock->rate_time, &now);
+ uint32_t pps;
+ pps = rad_pps(&sock->rate_pps_old, &sock->rate_pps_now, &sock->rate_time, &now);
if (pps > sock->max_rate) {
DEBUG("Dropping request due to rate limiting");
return 0;
request->password = pairfind(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
fun(request);
- request->listener->send(request->listener, request);
+
+ if (request->reply->code != 0) {
+ request->listener->send(request->listener, request);
+ } else {
+ RDEBUG("Not sending reply");
+ }
request_free(&request);
return 1;
}
/*
* Create and initialize the new request.
*/
- request = request_alloc(listener);
+ request = request_alloc(NULL);
request->reply = rad_alloc(request, 0);
if (!request->reply) {
ERROR("No memory");
request->priority = listener->type;
request->master_state = REQUEST_ACTIVE;
#ifdef DEBUG_STATE_MACHINE
- if (debug_flag) printf("(%u) ********\tSTATE %s C%u -> C%u\t********\n", request->number, __FUNCTION__, request->child_state, REQUEST_ACTIVE);
+ if (debug_flag) printf("(%u) ********\tSTATE %s C-%s -> C-%s\t********\n",
+ request->number, __FUNCTION__,
+ child_state_names[request->child_state],
+ child_state_names[REQUEST_RUNNING]);
#endif
- request->child_state = REQUEST_ACTIVE;
+ request->child_state = REQUEST_RUNNING;
request->handle = fun;
-#ifdef HAVE_PTHREAD_H
- request->child_pid = NO_SUCH_CHILD_PID;
-#endif
+ NO_CHILD_THREAD;
#ifdef WITH_STATS
request->listener->stats.last_packet = request->packet->timestamp.tv_sec;
- if (packet->code == PW_AUTHENTICATION_REQUEST) {
+ if (packet->code == PW_CODE_AUTHENTICATION_REQUEST) {
request->client->auth.last_packet = request->packet->timestamp.tv_sec;
radius_auth_stats.last_packet = request->packet->timestamp.tv_sec;
#ifdef WITH_ACCOUNTING
- } else if (packet->code == PW_ACCOUNTING_REQUEST) {
+ } else if (packet->code == PW_CODE_ACCOUNTING_REQUEST) {
request->client->acct.last_packet = request->packet->timestamp.tv_sec;
radius_acct_stats.last_packet = request->packet->timestamp.tv_sec;
#endif
/*
* Status-Server packets go to the head of the queue.
*/
- if (request->packet->code == PW_STATUS_SERVER) request->priority = 0;
+ if (request->packet->code == PW_CODE_STATUS_SERVER) request->priority = 0;
/*
* Set virtual server identity
request->server = NULL;
}
- request->root = &mainconfig;
+ request->root = &main_config;
#ifdef WITH_TCP
request->listener->count++;
#endif
char buffer[256];
fr_socket_limit_t *limit;
+ ASSERT_MASTER;
+
fr_event_now(el, &now);
if (listener->status != RAD_LISTEN_STATUS_KNOWN) return;
*
***********************************************************************/
+/*
+ * Called with the proxy mutex held
+ */
static void remove_from_proxy_hash_nl(REQUEST *request, bool yank)
{
if (!request->in_proxy_hash) return;
}
#ifdef WITH_TCP
+ rad_assert(request->proxy_listener != NULL);
request->proxy_listener->count--;
#endif
request->proxy_listener = NULL;
remove_from_proxy_hash_nl(request, true);
- PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
}
static int insert_into_proxy_hash(REQUEST *request)
for (tries = 0; tries < 2; tries++) {
rad_listen_t *this;
+ listen_socket_t *sock;
RDEBUG3("proxy: Trying to allocate ID (%d/2)", tries);
rcode = fr_packet_list_id_alloc(proxy_list,
this = proxy_new_listener(request->home_server, 0);
if (!this) {
PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
- ERROR("proxy: Failed to create a new outbound socket");
goto fail;
}
request->proxy->src_port = 0; /* Use any new socket */
proxy_listener = this;
+ sock = this->data;
+ if (!fr_packet_list_socket_add(proxy_list, this->fd,
+ sock->proto,
+ &sock->other_ipaddr, sock->other_port,
+ this)) {
+
+#ifdef HAVE_PTHREAD_H
+ proxy_no_new_sockets = true;
+#endif
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+
+ /*
+ * This is bad. However, the
+ * packet list now supports 256
+ * open sockets, which should
+ * minimize this problem.
+ */
+ ERROR("Failed adding proxy socket: %s",
+ fr_strerror());
+ goto fail;
+ }
+
/*
- * Add it to the event loop (and to the packet list)
- * before we try to grab another Id.
+ * Add it to the event loop. Ensure that we have
+ * only one mutex locked at a time.
*/
PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
- if (!event_new_fd(this)) {
- RDEBUG3("proxy: Failed inserting new socket into event loop");
- listen_free(&this);
- goto fail;
- }
+ radius_update_listener(this);
PTHREAD_MUTEX_LOCK(&proxy_mutex);
}
PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
- RDEBUG3(" proxy: allocating destination %s port %d - Id %d",
+ RDEBUG3("proxy: allocating destination %s port %d - Id %d",
inet_ntop(request->proxy->dst_ipaddr.af,
&request->proxy->dst_ipaddr.ipaddr, buf, sizeof(buf)),
request->proxy->dst_port,
return 1;
}
-static int process_proxy_reply(REQUEST *request)
+static int process_proxy_reply(REQUEST *request, RADIUS_PACKET *reply)
{
int rcode;
int post_proxy_type = 0;
VALUE_PAIR *vp;
/*
+ * There may be a proxy reply, but it may be too late.
+ */
+ if (!request->proxy_listener) return 0;
+
+ /*
* Delete any reply we had accumulated until now.
*/
pairfree(&request->reply->vps);
* If we have a proxy_reply, and it was a reject, setup
* post-proxy-type Reject
*/
- if (!vp && request->proxy_reply &&
- request->proxy_reply->code == PW_AUTHENTICATION_REJECT) {
- DICT_VALUE *dval;
+ if (!vp && reply &&
+ reply->code == PW_CODE_AUTHENTICATION_REJECT) {
+ DICT_VALUE *dval;
dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Reject");
if (dval) {
if (vp) {
post_proxy_type = vp->vp_integer;
- RDEBUG2(" Found Post-Proxy-Type %s",
- dict_valnamebyattr(PW_POST_PROXY_TYPE, 0,
- post_proxy_type));
+ RDEBUG2("Found Post-Proxy-Type %s", dict_valnamebyattr(PW_POST_PROXY_TYPE, 0, post_proxy_type));
+ }
+
+ if (reply) {
+ /*
+ * Decode the packet.
+ */
+ rcode = request->proxy_listener->decode(request->proxy_listener, request);
+ DEBUG_PACKET(request, reply, 0);
+
+ /*
+ * Pro-actively remove it from the proxy hash.
+ * This is later than in 2.1.x, but it means that
+ * the replies are authenticated before being
+ * removed from the hash.
+ */
+ if ((rcode == 0) &&
+ (request->num_proxied_requests <= request->num_proxied_responses)) {
+ remove_from_proxy_hash(request);
+ }
+ } else {
+ remove_from_proxy_hash(request);
}
if (request->home_pool && request->home_pool->virtual_server) {
char const *old_server = request->server;
request->server = request->home_pool->virtual_server;
- RDEBUG2(" server %s {", request->server);
+ RDEBUG2("server %s {", request->server);
+ RINDENT();
rcode = process_post_proxy(post_proxy_type, request);
- RDEBUG2(" }");
+ REXDENT();
+ RDEBUG2("}");
request->server = old_server;
} else {
rcode = process_post_proxy(post_proxy_type, request);
* There may NOT be a proxy reply, as we may be
* running Post-Proxy-Type = Fail.
*/
- if (request->proxy_reply) {
+ if (reply) {
+ request->reply->vps = paircopy(request->reply, reply->vps);
+
/*
* Delete the Proxy-State Attributes from
* the reply. These include Proxy-State
* attributes from us and remote server.
*/
- pairdelete(&request->proxy_reply->vps, PW_PROXY_STATE, 0, TAG_ANY);
-
- /*
- * Add the attributes left in the proxy
- * reply to the reply list.
- */
- pairfilter(request->reply, &request->reply->vps,
- &request->proxy_reply->vps, 0, 0, TAG_ANY);
-
- /*
- * Free proxy request pairs.
- */
- pairfree(&request->proxy->vps);
+ pairdelete(&request->reply->vps, PW_PROXY_STATE, 0, TAG_ANY);
}
switch (rcode) {
/*
* Status-Server packets don't count as real packets.
*/
- if (request->proxy->code != PW_STATUS_SERVER) {
+ if (request->proxy->code != PW_CODE_STATUS_SERVER) {
listen_socket_t *sock = request->proxy_listener->data;
request->home_server->last_packet_recv = now.tv_sec;
* Call the state machine to do something useful with the
* request.
*/
- request->proxy_reply = packet;
+ request->proxy_reply = talloc_steal(request, packet);
packet->timestamp = now;
request->priority = RAD_LISTEN_PROXY;
request->home_server->stats.last_packet = packet->timestamp.tv_sec;
request->proxy_listener->stats.last_packet = packet->timestamp.tv_sec;
- if (request->proxy->code == PW_AUTHENTICATION_REQUEST) {
+ if (request->proxy->code == PW_CODE_AUTHENTICATION_REQUEST) {
proxy_auth_stats.last_packet = packet->timestamp.tv_sec;
#ifdef WITH_ACCOUNTING
- } else if (request->proxy->code == PW_ACCOUNTING_REQUEST) {
+ } else if (request->proxy->code == PW_CODE_ACCOUNTING_REQUEST) {
proxy_acct_stats.last_packet = packet->timestamp.tv_sec;
#endif
}
*/
if (request->parent) {
rad_assert(request->parent->coa == request);
- rad_assert((request->proxy->code == PW_COA_REQUEST) ||
- (request->proxy->code == PW_DISCONNECT_REQUEST));
+ rad_assert((request->proxy->code == PW_CODE_COA_REQUEST) ||
+ (request->proxy->code == PW_CODE_DISCONNECT_REQUEST));
rad_assert(request->process != NULL);
request_coa_separate(request);
}
DICT_VALUE const *dval = NULL;
VALUE_PAIR *vp;
- if (request->proxy->code == PW_AUTHENTICATION_REQUEST) {
+ if (request->proxy->code == PW_CODE_AUTHENTICATION_REQUEST) {
dval = dict_valbyname(PW_POST_PROXY_TYPE, 0,
"Fail-Authentication");
- } else if (request->proxy->code == PW_ACCOUNTING_REQUEST) {
+ } else if (request->proxy->code == PW_CODE_ACCOUNTING_REQUEST) {
dval = dict_valbyname(PW_POST_PROXY_TYPE, 0,
"Fail-Accounting");
#ifdef WITH_COA
- } else if (request->proxy->code == PW_COA_REQUEST) {
+ } else if (request->proxy->code == PW_CODE_COA_REQUEST) {
dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Fail-CoA");
- } else if (request->proxy->code == PW_DISCONNECT_REQUEST) {
+ } else if (request->proxy->code == PW_CODE_DISCONNECT_REQUEST) {
dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Fail-Disconnect");
#endif
} else {
- WDEBUG("Unknown packet type in Post-Proxy-Type Fail: ignoring");
+ WARN("Unknown packet type in Post-Proxy-Type Fail: ignoring");
return 0;
}
if (!dval) dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Fail");
if (!dval) {
- DEBUG("No Post-Proxy-Type Fail: ignoring");
pairdelete(&request->config_items, PW_POST_PROXY_TYPE, 0, TAG_ANY);
return 0;
}
return 1;
}
-STATE_MACHINE_DECL(proxy_running)
+STATE_MACHINE_DECL(proxy_no_reply)
{
TRACE_STATE_MACHINE;
break;
case FR_ACTION_RUN:
- request_running(request, FR_ACTION_PROXY_REPLY);
+ if (process_proxy_reply(request, NULL)) {
+ request_finish(request, action);
+ }
+ request_done(request, FR_ACTION_DONE);
break;
default:
}
}
-STATE_MACHINE_DECL(request_virtual_server)
+STATE_MACHINE_DECL(proxy_running)
{
- char const *old;
-
TRACE_STATE_MACHINE;
switch (action) {
break;
case FR_ACTION_RUN:
- old = request->server;
- request->server = request->home_server->server;
- request_running(request, action);
- request->server = old;
+ if (process_proxy_reply(request, request->proxy_reply)) {
+ request->handle(request);
+ request_finish(request, action);
+ } else {
+ request_done(request, FR_ACTION_DONE);
+ }
break;
default:
}
}
-
static int request_will_proxy(REQUEST *request)
{
int rcode, pre_proxy_type = 0;
char const *realmname = NULL;
VALUE_PAIR *vp, *strippedname;
- home_server *home;
+ home_server_t *home;
REALM *realm = NULL;
home_pool_t *pool = NULL;
if (!request->root->proxy_requests) return 0;
if (request->packet->dst_port == 0) return 0;
- if (request->packet->code == PW_STATUS_SERVER) return 0;
+ if (request->packet->code == PW_CODE_STATUS_SERVER) return 0;
if (request->in_proxy_hash) return 0;
/*
/*
* Figure out which pool to use.
*/
- if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
+ if (request->packet->code == PW_CODE_AUTHENTICATION_REQUEST) {
pool = realm->auth_pool;
#ifdef WITH_ACCOUNTING
- } else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
+ } else if (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) {
pool = realm->acct_pool;
#endif
#ifdef WITH_COA
- } else if ((request->packet->code == PW_COA_REQUEST) ||
- (request->packet->code == PW_DISCONNECT_REQUEST)) {
+ } else if ((request->packet->code == PW_CODE_COA_REQUEST) ||
+ (request->packet->code == PW_CODE_DISCONNECT_REQUEST)) {
pool = realm->coa_pool;
#endif
if (!vp) return 0;
switch (request->packet->code) {
- case PW_AUTHENTICATION_REQUEST:
+ case PW_CODE_AUTHENTICATION_REQUEST:
pool_type = HOME_TYPE_AUTH;
break;
#ifdef WITH_ACCOUNTING
- case PW_ACCOUNTING_REQUEST:
+ case PW_CODE_ACCOUNTING_REQUEST:
pool_type = HOME_TYPE_ACCT;
break;
#endif
#ifdef WITH_COA
- case PW_COA_REQUEST:
- case PW_DISCONNECT_REQUEST:
+ case PW_CODE_COA_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
pool_type = HOME_TYPE_COA;
break;
#endif
vp = pairfind(request->proxy->vps, PW_USER_NAME, 0, TAG_ANY);
if (!vp) {
vp_cursor_t cursor;
- vp = radius_paircreate(request, NULL,
+ vp = radius_paircreate(NULL, NULL,
PW_USER_NAME, 0);
rad_assert(vp != NULL); /* handled by above function */
/* Insert at the START of the list */
/* FIXME: Can't make assumptions about ordering */
- paircursor(&cursor, &vp);
- pairinsert(&cursor, request->proxy->vps);
+ fr_cursor_init(&cursor, &vp);
+ fr_cursor_insert(&cursor, request->proxy->vps);
request->proxy->vps = vp;
}
pairstrcpy(vp, strippedname->vp_strvalue);
* since we can't use the request authenticator
* anymore - we changed it.
*/
- if ((request->packet->code == PW_AUTHENTICATION_REQUEST) &&
+ if ((request->packet->code == PW_CODE_AUTHENTICATION_REQUEST) &&
pairfind(request->proxy->vps, PW_CHAP_PASSWORD, 0, TAG_ANY) &&
pairfind(request->proxy->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY) == NULL) {
- uint8_t *p;
- vp = radius_paircreate(request, &request->proxy->vps,
- PW_CHAP_CHALLENGE, 0);
- vp->length = sizeof(request->packet->vector);
- vp->vp_octets = p = talloc_array(vp, uint8_t, vp->length);
-
- memcpy(p, request->packet->vector,
- sizeof(request->packet->vector));
+ vp = radius_paircreate(request->proxy, &request->proxy->vps, PW_CHAP_CHALLENGE, 0);
+ pairmemcpy(vp, request->packet->vector, sizeof(request->packet->vector));
}
/*
* The RFC's say we have to do this, but FreeRADIUS
* doesn't need it.
*/
- vp = radius_paircreate(request, &request->proxy->vps,
- PW_PROXY_STATE, 0);
+ vp = radius_paircreate(request->proxy, &request->proxy->vps, PW_PROXY_STATE, 0);
pairsprintf(vp, "%u", request->packet->id);
/*
*/
vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE, 0, TAG_ANY);
if (vp) {
- RDEBUG2(" Found Pre-Proxy-Type %s", vp->vp_strvalue);
+ DICT_VALUE const *dval = dict_valbyattr(vp->da->attr, vp->da->vendor, vp->vp_integer);
+ /* Must be a validation issue */
+ rad_assert(dval);
+ RDEBUG2("Found Pre-Proxy-Type %s", dval->name);
pre_proxy_type = vp->vp_integer;
}
char const *old_server = request->server;
request->server = request->home_pool->virtual_server;
- RDEBUG2(" server %s {", request->server);
+
+ RDEBUG2("server %s {", request->server);
+ RINDENT();
rcode = process_pre_proxy(pre_proxy_type, request);
- RDEBUG2(" }");
- request->server = old_server;
+ REXDENT();
+ RDEBUG2("}");
+
+ request->server = old_server;
} else {
rcode = process_pre_proxy(pre_proxy_type, request);
}
#endif
/*
- * The request may be sent to a virtual server. If we're
- * in a child thread, just process it here. If we're the
- * master, push it back onto the queue for later
- * processing.
+ * The request may need sending to a virtual server.
+ * This code is more than a little screwed up. The rest
+ * of the state machine doesn't handle parent / child
+ * relationships well. i.e. if the child request takes
+ * too long, the core will mark the *parent* as "stop
+ * processing". And the child will continue without
+ * knowing anything...
+ *
+ * So, we have some horrible hacks to get around that.
*/
if (request->home_server->server) {
+ REQUEST *fake;
+
+ if (request->packet->dst_port == 0) {
+ WARN("Cannot proxy an internal request");
+ return 0;
+ }
+
DEBUG("Proxying to virtual server %s",
request->home_server->server);
- if (!we_are_master()) {
- request_virtual_server(request, FR_ACTION_RUN);
-#ifdef HAVE_PTHREAD_H
- request->child_pid = NO_SUCH_CHILD_PID;
-#endif
- return 1;
- }
+ /*
+ * Packets to virtual serrers don't get
+ * retransmissions sent to them. And the virtual
+ * server is run ONLY if we have no child
+ * threads, or we're running in a child thread.
+ */
+ rad_assert(retransmit == 0);
+ rad_assert(!spawn_flag || !we_are_master());
- request_queue_or_run(request, request_virtual_server);
- return 1;
+ fake = request_alloc_fake(request);
+
+ fake->packet->vps = paircopy(fake->packet, request->packet->vps);
+ talloc_free(request->proxy);
+
+ fake->server = request->home_server->server;
+ fake->handle = request->handle;
+ fake->process = NULL; /* should never be run for anything */
+
+ /*
+ * Run the virtual server.
+ */
+ request_running(fake, FR_ACTION_RUN);
+
+ request->proxy = talloc_steal(request, fake->packet);
+ fake->packet = NULL;
+ request->proxy_reply = talloc_steal(request, fake->reply);
+ fake->reply = NULL;
+
+ request_free(&fake);
+
+ /*
+ * Just do the work here, rather than trying to
+ * run the "decode proxy reply" stuff...
+ */
+ process_proxy_reply(request, request->proxy_reply);
+
+ request->handle(request); /* to do more post-proxy stuff */
+
+ return -1; /* so we call request_finish */
}
/*
* We're actually sending a proxied packet. Do that now.
*/
if (!request->in_proxy_hash && !insert_into_proxy_hash(request)) {
- RPROXY("Failed to insert initial packet into the proxy list.");
+ ERROR("Failed to insert request into the proxy list");
return -1;
}
rad_assert(request->proxy->id >= 0);
+#ifdef WITH_TLS
+ if (request->home_server->tls) {
+ RDEBUG2("Proxying request to home server %s port %d (TLS)",
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port);
+ } else
+#endif
RDEBUG2("Proxying request to home server %s port %d",
inet_ntop(request->proxy->dst_ipaddr.af,
&request->proxy->dst_ipaddr.ipaddr,
request->home_server->last_packet_sent = request->proxy_retransmit.tv_sec;
}
-#ifdef HAVE_PTHREAD_H
- request->child_pid = NO_SUCH_CHILD_PID;
-#endif
FR_STATS_TYPE_INC(request->home_server->stats.total_requests);
+ NO_CHILD_THREAD;
+ request->child_state = REQUEST_PROXIED;
request->proxy_listener->send(request->proxy_listener,
request);
return 1;
*/
static int request_proxy_anew(REQUEST *request)
{
- home_server *home;
+ home_server_t *home;
/*
* Delete the request from the proxy list.
home_server_update_request(home, request);
if (!insert_into_proxy_hash(request)) {
- RPROXY("Failed to insert retransmission into the proxy list.");
+ RPROXY("Failed to insert retransmission into the proxy list");
goto post_proxy_fail;
}
/*
* Update the Acct-Delay-Time attribute.
*/
- if (request->packet->code == PW_ACCOUNTING_REQUEST) {
+ if (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) {
VALUE_PAIR *vp;
vp = pairfind(request->proxy->vps, PW_ACCT_DELAY_TIME, 0, TAG_ANY);
- if (!vp) vp = radius_paircreate(request,
+ if (!vp) vp = radius_paircreate(request->proxy,
&request->proxy->vps,
PW_ACCT_DELAY_TIME, 0);
if (vp) {
STATE_MACHINE_DECL(request_ping)
{
- home_server *home = request->home_server;
+ home_server_t *home = request->home_server;
char buffer[128];
TRACE_STATE_MACHINE;
if (home->state == HOME_STATE_ALIVE) break;
/*
- * We haven't received enough ping responses to mark it
- * "alive". Wait a bit.
+ * It's dead, and we haven't received enough ping
+ * responses to mark it "alive". Wait a bit.
+ *
+ * If it's zombie, we mark it alive immediately.
*/
- if (home->num_received_pings < home->num_pings_to_alive) {
- break;
+ if ((home->state == HOME_STATE_IS_DEAD) &&
+ (home->num_received_pings < home->num_pings_to_alive)) {
+ return;
}
/*
* pings.
*/
home->state = HOME_STATE_ALIVE;
- exec_trigger(request, request->home_server->cs, "home_server.alive", false);
+ exec_trigger(request, home->cs, "home_server.alive", false);
home->currently_outstanding = 0;
home->num_sent_pings = 0;
home->num_received_pings = 0;
*/
static void ping_home_server(void *ctx)
{
- home_server *home = ctx;
+ home_server_t *home = ctx;
REQUEST *request;
VALUE_PAIR *vp;
struct timeval when, now;
request = request_alloc(NULL);
request->number = request_num_counter++;
-#ifdef HAVE_PTHREAD_H
- request->child_pid = NO_SUCH_CHILD_PID;
-#endif
+ NO_CHILD_THREAD;
request->proxy = rad_alloc(request, 1);
rad_assert(request->proxy != NULL);
if (home->ping_check == HOME_PING_CHECK_STATUS_SERVER) {
- request->proxy->code = PW_STATUS_SERVER;
+ request->proxy->code = PW_CODE_STATUS_SERVER;
pairmake(request->proxy, &request->proxy->vps,
"Message-Authenticator", "0x00", T_OP_SET);
} else if (home->type == HOME_TYPE_AUTH) {
- request->proxy->code = PW_AUTHENTICATION_REQUEST;
+ request->proxy->code = PW_CODE_AUTHENTICATION_REQUEST;
pairmake(request->proxy, &request->proxy->vps,
"User-Name", home->ping_user_name, T_OP_SET);
} else {
#ifdef WITH_ACCOUNTING
- request->proxy->code = PW_ACCOUNTING_REQUEST;
+ request->proxy->code = PW_CODE_ACCOUNTING_REQUEST;
pairmake(request->proxy, &request->proxy->vps,
"User-Name", home->ping_user_name, T_OP_SET);
request->proxy->dst_port = home->port;
request->home_server = home;
#ifdef DEBUG_STATE_MACHINE
- if (debug_flag) printf("(%u) ********\tSTATE %s C%u -> C%u\t********\n", request->number, __FUNCTION__, request->child_state, REQUEST_DONE);
+ if (debug_flag) printf("(%u) ********\tSTATE %s C-%s -> C-%s\t********\n", request->number, __FUNCTION__,
+ child_state_names[request->child_state],
+ child_state_names[REQUEST_DONE]);
if (debug_flag) printf("(%u) ********\tNEXT-STATE %s -> %s\n", request->number, __FUNCTION__, "request_ping");
#endif
#ifdef HAVE_PTHREAD_H
INSERT_EVENT(ping_home_server, home);
}
-static void home_trigger(home_server *home, char const *trigger)
+static void home_trigger(home_server_t *home, char const *trigger)
{
REQUEST my_request;
RADIUS_PACKET my_packet;
exec_trigger(&my_request, home->cs, trigger, false);
}
-static void mark_home_server_zombie(home_server *home)
+static void mark_home_server_zombie(home_server_t *home, struct timeval *now, struct timeval *response_window)
{
+ time_t start;
char buffer[128];
ASSERT_MASTER;
#ifdef WITH_TCP
if (home->proto == IPPROTO_TCP) {
- WDEBUG("Not marking TCP server %s zombie", home->name);
+ WARN("Not marking TCP server %s zombie", home->name);
return;
}
#endif
+ /*
+ * We've received a real packet recently. Don't mark the
+ * server as zombie until we've received NO packets for a
+ * while. The "1/4" of zombie period was chosen rather
+ * arbitrarily. It's a balance between too short, which
+ * gives quick fail-over and fail-back, or too long,
+ * where the proxy still sends packets to an unresponsive
+ * home server.
+ */
+ start = now->tv_sec - ((home->zombie_period + 3) / 4);
+ if (home->last_packet_recv >= start) {
+ DEBUG("Recieved reply from home server %d seconds ago. Might not be zombie.",
+ (int) (now->tv_sec - home->last_packet_recv));
+ return;
+ }
+
home->state = HOME_STATE_ZOMBIE;
home_trigger(home, "home_server.zombie");
/*
- * Back-date the zombie period to when we last expected
- * to see a response. i.e. when we last sent a request.
+ * Set the home server to "zombie", as of the time
+ * calculated above.
*/
- if (home->last_packet_sent == 0) {
- gettimeofday(&home->zombie_period_start, NULL);
- } else {
- home->zombie_period_start.tv_sec = home->last_packet_sent;
- home->zombie_period_start.tv_usec = 0;
- }
+ home->zombie_period_start.tv_sec = start;
+ home->zombie_period_start.tv_usec = USEC / 2;
fr_event_delete(el, &home->ev);
home->num_sent_pings = 0;
home->num_received_pings = 0;
- PROXY( "Marking home server %s port %d as zombie (it has not responded in %d seconds).",
+ PROXY( "Marking home server %s port %d as zombie (it has not responded in %d.%06d seconds).",
inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
buffer, sizeof(buffer)),
- home->port, home->response_window);
+ home->port, (int) response_window->tv_sec, (int) response_window->tv_usec);
ping_home_server(home);
}
void revive_home_server(void *ctx)
{
- home_server *home = ctx;
+ home_server_t *home = ctx;
char buffer[128];
#ifdef WITH_TCP
home->port);
}
-void mark_home_server_dead(home_server *home, struct timeval *when)
+void mark_home_server_dead(home_server_t *home, struct timeval *when)
{
int previous_state = home->state;
char buffer[128];
#ifdef WITH_TCP
if (home->proto == IPPROTO_TCP) {
- WDEBUG("Not marking TCP server dead");
+ WARN("Not marking TCP server dead");
return;
}
#endif
STATE_MACHINE_DECL(proxy_wait_for_reply)
{
struct timeval now, when;
- home_server *home = request->home_server;
+ struct timeval *response_window = NULL;
+ home_server_t *home = request->home_server;
char buffer[128];
TRACE_STATE_MACHINE;
- rad_assert(request->packet->code != PW_STATUS_SERVER);
+ rad_assert(request->packet->code != PW_CODE_STATUS_SERVER);
rad_assert(request->home_server != NULL);
if (request->master_state == REQUEST_STOP_PROCESSING) {
switch (action) {
case FR_ACTION_DUP:
+ /*
+ * We have a reply, ignore the retransmit.
+ */
if (request->proxy_reply) return;
+ /*
+ * The request was proxied to a virtual server.
+ * Ignore the retransmit.
+ */
+ if (request->home_server->server) return;
+
if ((home->state == HOME_STATE_IS_DEAD) ||
!request->proxy_listener ||
(request->proxy_listener->status != RAD_LISTEN_STATUS_KNOWN)) {
#ifdef WITH_TCP
if (home->proto == IPPROTO_TCP) {
- DEBUG2("Suppressing duplicate proxied request to home server %s port %d proto TCP - ID: %d",
+ DEBUG2("Suppressing duplicate proxied request (tcp) to home server %s port %d proto TCP - ID: %d",
inet_ntop(request->proxy->dst_ipaddr.af,
&request->proxy->dst_ipaddr.ipaddr,
buffer, sizeof(buffer)),
}
#endif
+ /*
+ * More than one retransmit a second is stupid,
+ * and should be suppressed by the proxy.
+ */
+ when = request->proxy_retransmit;
+ when.tv_sec++;
+
+ if (timercmp(&now, &when, <)) {
+ DEBUG2("Suppressing duplicate proxied request (too fast) to home server %s port %d proto TCP - ID: %d",
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port,
+ request->proxy->id);
+ return;
+ }
+
#ifdef WITH_ACCOUNTING
/*
* If we update the Acct-Delay-Time, we need to
* get a new ID.
*/
- if ((request->packet->code == PW_ACCOUNTING_REQUEST) &&
+ if ((request->packet->code == PW_CODE_ACCOUNTING_REQUEST) &&
pairfind(request->proxy->vps, PW_ACCT_DELAY_TIME, 0, TAG_ANY)) {
request_proxy_anew(request);
return;
DEBUG_PACKET(request, request->proxy, 1);
FR_STATS_TYPE_INC(home->stats.total_requests);
home->last_packet_sent = now.tv_sec;
+ request->proxy_retransmit = now;
request->proxy_listener->send(request->proxy_listener,
request);
break;
case FR_ACTION_TIMER:
- /*
- * Wake up "response_window" time in the future.
- * i.e. when MY packet hasn't received a response.
- *
- * Note that we DO NOT mark the home server as
- * zombie if it doesn't respond to us. It may be
- * responding to other (better looking) packets.
- */
- when = request->proxy->timestamp;
- when.tv_sec += home->response_window;
+ response_window = request_response_window(request);
- /*
- * Not at the response window. Set the timer for
- * that.
- */
- if (timercmp(&when, &now, >)) {
- RDEBUG("Expecting proxy response no later than %d seconds from now", home->response_window);
- STATE_MACHINE_TIMER(FR_ACTION_TIMER);
- return;
+#ifdef WITH_TCP
+ if (!request->proxy_listener ||
+ (request->proxy_listener->status != RAD_LISTEN_STATUS_KNOWN)) {
+ remove_from_proxy_hash(request);
+
+ when = request->packet->timestamp;
+ when.tv_sec += request->root->max_request_time;
+
+ if (timercmp(&when, &now, >)) {
+ RDEBUG("Waiting for client retransmission in order to do a proxy retransmit");
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+ return;
+ }
+ } else
+#endif
+ {
+ /*
+ * Wake up "response_window" time in the future.
+ * i.e. when MY packet hasn't received a response.
+ *
+ * Note that we DO NOT mark the home server as
+ * zombie if it doesn't respond to us. It may be
+ * responding to other (better looking) packets.
+ */
+ when = request->proxy->timestamp;
+ timeradd(&when, response_window, &when);
+
+ /*
+ * Not at the response window. Set the timer for
+ * that.
+ */
+ if (timercmp(&when, &now, >)) {
+ RDEBUG("Expecting proxy response no later than %d.%06d seconds from now",
+ (int) response_window->tv_sec, (int) response_window->tv_usec);
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+ return;
+ }
}
RDEBUG("No proxy response, giving up on request and marking it done");
* server state machine.
*/
if (((home->state == HOME_STATE_ALIVE) ||
- (home->state == HOME_STATE_UNKNOWN)) &&
+ (home->state == HOME_STATE_UNKNOWN))
#ifdef WITH_TCP
- (home->proto != IPPROTO_TCP) &&
+ && (home->proto != IPPROTO_TCP)
#endif
- ((home->last_packet_recv + home->response_window) <= now.tv_sec)) {
- mark_home_server_zombie(home);
+ ) {
+ mark_home_server_zombie(home, &now, response_window);
}
FR_STATS_TYPE_INC(home->stats.total_timeouts);
* may have failed over to another home server.
* But that one may be dead, too.
*/
- RERROR("Failing request due to lack of any response from home server %s port %d",
+ RERROR("Failing proxied request, due to lack of any response from home server %s port %d",
inet_ntop(request->proxy->dst_ipaddr.af,
&request->proxy->dst_ipaddr.ipaddr,
buffer, sizeof(buffer)),
request->proxy->dst_port);
- if (!setup_post_proxy_fail(request)) {
+ if (setup_post_proxy_fail(request)) {
+ request_queue_or_run(request, proxy_no_reply);
+ } else {
gettimeofday(&request->reply->timestamp, NULL);
request_cleanup_delay_init(request, NULL);
- return;
}
- /* FALL-THROUGH */
+ break;
/*
* Duplicate proxy replies have been quenched by
if (vp) {
if (vp->vp_integer == 0) {
fail:
- request_done(request->coa, FR_ACTION_DONE);
+ request_free(&request->coa);
return;
}
}
home_server_update_request(coa->home_server, coa);
} else if (!coa->home_server) {
- int port = PW_COA_UDP_PORT;
+ uint16_t port = PW_COA_UDP_PORT;
vp = pairfind(coa->proxy->vps, PW_PACKET_DST_PORT, 0, TAG_ANY);
if (vp) port = vp->vp_integer;
vp = pairfind(coa->proxy->vps, PW_PACKET_TYPE, 0, TAG_ANY);
if (vp) {
switch (vp->vp_integer) {
- case PW_COA_REQUEST:
- case PW_DISCONNECT_REQUEST:
+ case PW_CODE_COA_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
coa->proxy->code = vp->vp_integer;
break;
}
}
- if (!coa->proxy->code) coa->proxy->code = PW_COA_REQUEST;
+ if (!coa->proxy->code) coa->proxy->code = PW_CODE_COA_REQUEST;
/*
* The rest of the server code assumes that
*/
rad_assert(coa->packet != NULL);
rad_assert(coa->packet->vps == NULL);
- memcpy(coa->packet, request->packet, sizeof(*request->packet));
- coa->packet->vps = paircopy(coa->packet, request->packet->vps);
- coa->packet->data = NULL;
- rad_assert(coa->reply != NULL);
- rad_assert(coa->reply->vps == NULL);
- memcpy(coa->reply, request->reply, sizeof(*request->reply));
- coa->reply->vps = paircopy(coa->reply, request->reply->vps);
- coa->reply->data = NULL;
+
+ coa->packet = rad_copy_packet(coa, request->packet);
+ coa->reply = rad_copy_packet(coa, request->reply);
+
coa->config_items = paircopy(coa, request->config_items);
coa->num_coa_requests = 0;
coa->handle = null_handler;
- coa->number = request->number ^ (1 << 24);
+ coa->number = request->number; /* it's associated with the same request */
/*
* Call the pre-proxy routines.
*/
vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE, 0, TAG_ANY);
if (vp) {
- RDEBUG2(" Found Pre-Proxy-Type %s", vp->vp_strvalue);
+ DICT_VALUE const *dval = dict_valbyattr(vp->da->attr, vp->da->vendor, vp->vp_integer);
+ /* Must be a validation issue */
+ rad_assert(dval);
+ RDEBUG2("Found Pre-Proxy-Type %s", dval->name);
pre_proxy_type = vp->vp_integer;
}
char const *old_server = coa->server;
coa->server = coa->home_pool->virtual_server;
- RDEBUG2(" server %s {", coa->server);
+ RDEBUG2("server %s {", coa->server);
+ RINDENT();
rcode = process_pre_proxy(pre_proxy_type, coa);
- RDEBUG2(" }");
+ REXDENT();
+ RDEBUG2("}");
coa->server = old_server;
} else {
rcode = process_pre_proxy(pre_proxy_type, coa);
coa->proxy->dst_port = coa->home_server->port;
if (!insert_into_proxy_hash(coa)) {
- radlog_request(L_PROXY, 0, coa, "Failed to insert CoA request into proxy list.");
+ radlog_request(L_PROXY, 0, coa, "Failed to insert CoA request into proxy list");
goto fail;
}
DEBUG_PACKET(coa, coa->proxy, 1);
- coa->process = request_coa_process;
+ coa->process = coa_wait_for_reply;
#ifdef DEBUG_STATE_MACHINE
- if (debug_flag) printf("(%u) ********\tSTATE %s C%u -> C%u\t********\n", request->number, __FUNCTION__, request->child_state, REQUEST_ACTIVE);
+ if (debug_flag) printf("(%u) ********\tSTATE %s C-%s -> C-%s\t********\n", request->number, __FUNCTION__,
+ child_state_names[request->child_state],
+ child_state_names[REQUEST_RUNNING]);
+#endif
+#ifdef HAVE_PTHREAD_H
+ coa->child_pid = NO_SUCH_CHILD_PID;
#endif
- coa->child_state = REQUEST_ACTIVE;
+ coa->child_state = REQUEST_PROXIED;
rad_assert(coa->proxy_reply == NULL);
FR_STATS_TYPE_INC(coa->home_server->stats.total_requests);
coa->home_server->last_packet_sent = coa->proxy->timestamp.tv_sec;
}
-static void request_coa_separate(REQUEST *request)
+static void coa_timer(REQUEST *request)
{
-#ifdef DEBUG_STATE_MACHINE
- int action = FR_ACTION_TIMER;
-#endif
- TRACE_STATE_MACHINE;
-
- rad_assert(request->parent != NULL);
- rad_assert(request->parent->coa == request);
- rad_assert(request->ev == NULL);
- rad_assert(!request->in_request_hash);
-
- rad_assert(request->proxy_listener != NULL);
- request = talloc_steal(request->proxy_listener, request);
- request->parent->coa = NULL;
- request->parent = NULL;
-
- /*
- * Set up timers for the CoA request. These do all kinds
- * of different things....
- */
- request_coa_timer(request);
-}
-
-static void request_coa_timer(REQUEST *request)
-{
- int delay, frac;
+ uint32_t delay, frac;
struct timeval now, when, mrd;
rad_assert(request->parent == NULL);
*/
if (request->home_server->coa_mrc &&
(request->num_coa_requests >= request->home_server->coa_mrc)) {
- if (!setup_post_proxy_fail(request)) {
- return;
- }
+ char buffer[128];
- request_queue_or_run(request, proxy_running);
+ RERROR("Failing request - originate-coa ID %u, due to lack of any response from coa server %s port %d",
+ request->proxy->id,
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port);
+
+ if (setup_post_proxy_fail(request)) {
+ request_queue_or_run(request, coa_no_reply);
+ } else {
+ request_done(request, FR_ACTION_DONE);
+ }
return;
}
request);
}
-
-#ifdef HAVE_PTHREAD_H
-STATE_MACHINE_DECL(coa_running)
+STATE_MACHINE_DECL(coa_wait_for_reply)
{
+ rad_assert(request->parent == NULL);
+
TRACE_STATE_MACHINE;
switch (action) {
case FR_ACTION_TIMER:
- request_coa_timer(request);
+ /*
+ * This is big enough to be in it's own function.
+ */
+ coa_timer(request);
break;
case FR_ACTION_PROXY_REPLY:
+ rad_assert(request->parent == NULL);
+ request_queue_or_run(request, coa_running);
+ break;
+
+ default:
+ RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
+ break;
+ }
+}
+
+static void request_coa_separate(REQUEST *request)
+{
+#ifdef DEBUG_STATE_MACHINE
+ int action = FR_ACTION_TIMER;
+#endif
+ TRACE_STATE_MACHINE;
+
+ rad_assert(request->parent != NULL);
+ rad_assert(request->parent->coa == request);
+ rad_assert(request->ev == NULL);
+ rad_assert(!request->in_request_hash);
+ rad_assert(request->coa == NULL);
+
+ rad_assert(request->proxy_listener != NULL);
+
+ (void) talloc_steal(NULL, request);
+ request->parent->coa = NULL;
+ request->parent = NULL;
+
+ /*
+ * Should be coa_wait_for_reply()
+ */
+ request->process(request, FR_ACTION_TIMER);
+}
+
+STATE_MACHINE_DECL(coa_no_reply)
+{
+ char buffer[128];
+
+ TRACE_STATE_MACHINE;
+
+ switch (action) {
+ case FR_ACTION_TIMER:
request_common(request, action);
break;
+ case FR_ACTION_PROXY_REPLY: /* too late! */
+ RDEBUG2("Reply from CoA server %s port %d - ID: %d arrived too late.",
+ inet_ntop(request->proxy->src_ipaddr.af,
+ &request->proxy->src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port, request->proxy->id);
+ break;
+
case FR_ACTION_RUN:
- request_running(request, FR_ACTION_PROXY_REPLY);
+ /*
+ * FIXME: do recv_coa Fail
+ */
+ (void) process_proxy_reply(request, NULL);
+ request_done(request, FR_ACTION_DONE);
break;
default:
break;
}
}
-#endif /* HAVE_PTHREAD_H */
-
-/*
- * Process CoA requests that we originated.
- */
-STATE_MACHINE_DECL(request_coa_process)
+STATE_MACHINE_DECL(coa_running)
{
TRACE_STATE_MACHINE;
switch (action) {
case FR_ACTION_TIMER:
- request_coa_timer(request);
+ request_process_timer(request);
break;
case FR_ACTION_PROXY_REPLY:
- rad_assert(request->parent == NULL);
-#ifdef HAVE_PTHREAD_H
- /*
- * Catch the case of a proxy reply when called
- * from the main worker thread.
- */
- if (we_are_master() &&
- (request->process != coa_running)) {
- request_queue_or_run(request, coa_running);
- return;
- }
- /* FALL-THROUGH */
-#endif
+ request_common(request, action);
+ break;
+
case FR_ACTION_RUN:
- request_running(request, action);
+ if (process_proxy_reply(request, request->proxy_reply)) {
+ request->handle(request);
+ request_finish(request, action);
+ } else {
+ request_done(request, FR_ACTION_DONE);
+ }
break;
default:
break;
}
}
-
#endif /* WITH_COA */
/***********************************************************************
}
#ifdef WITH_DETAIL
+#ifdef WITH_DETAIL_THREAD
+#else
/*
* This function is called periodically to see if this detail
* file is available for reading.
fr_exit(1);
}
}
-#endif
+#endif /* WITH_DETAIL_THREAD */
+#endif /* WITH_DETAIL */
static void event_status(struct timeval *wake)
{
if (debug_flag == 0) {
if (just_started) {
- INFO("Ready to process requests.");
+ INFO("Ready to process requests");
just_started = false;
}
return;
}
if (!wake) {
- INFO("Ready to process requests.");
+ INFO("Ready to process requests");
} else if ((wake->tv_sec != 0) ||
(wake->tv_usec >= 100000)) {
}
+#ifdef WITH_TCP
+static void listener_free_cb(void *ctx)
+{
+ rad_listen_t *this = ctx;
+ char buffer[1024];
+
+ if (this->count > 0) {
+ struct timeval when;
+ listen_socket_t *sock = this->data;
+
+ fr_event_now(el, &when);
+ when.tv_sec += 3;
+
+ if (!fr_event_insert(el, listener_free_cb, this, &when,
+ &(sock->ev))) {
+ rad_panic("Failed to insert event");
+ }
-int event_new_fd(rad_listen_t *this)
+ return;
+ }
+
+ /*
+ * It's all free, close the socket.
+ */
+
+ this->print(this, buffer, sizeof(buffer));
+ DEBUG("... cleaning up socket %s", buffer);
+ listen_free(&this);
+}
+#endif
+
+#ifdef WITH_PROXY
+static int proxy_eol_cb(void *ctx, void *data)
+{
+ struct timeval when;
+ REQUEST *request = fr_packet2myptr(REQUEST, proxy, data);
+
+ if (request->proxy_listener != ctx) return 0;
+
+ /*
+ * We don't care if it's being processed in a child thread.
+ */
+
+#ifdef WITH_ACCOUNTING
+ /*
+ * Accounting packets should be deleted immediately.
+ * They will never be retransmitted by the client.
+ */
+ if (request->proxy->code == PW_CODE_ACCOUNTING_REQUEST) {
+ RDEBUG("Stopping request due to failed connection to home server");
+ request->master_state = REQUEST_STOP_PROCESSING;
+ }
+#endif
+
+ /*
+ * Reset the timer to be now, so that the request is
+ * quickly updated. But spread the requests randomly
+ * over the next second, so that we don't overload the
+ * server.
+ */
+ fr_event_now(el, &when);
+ tv_add(&when, fr_rand() % USEC);
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+
+ /*
+ * Don't delete it from the list.
+ */
+ return 0;
+}
+#endif
+
+static int event_new_fd(rad_listen_t *this)
{
char buffer[1024];
+ ASSERT_MASTER;
+
if (this->status == RAD_LISTEN_STATUS_KNOWN) return 1;
this->print(this, buffer, sizeof(buffer));
INFO(" ... adding new socket %s", buffer);
}
-#ifdef WITH_PROXY
- /*
- * Add it to the list of sockets we can use.
- * Server sockets (i.e. auth/acct) are never
- * added to the packet list.
- */
- if (this->type == RAD_LISTEN_PROXY) {
- PTHREAD_MUTEX_LOCK(&proxy_mutex);
- if (!fr_packet_list_socket_add(proxy_list, this->fd,
- sock->proto,
- &sock->other_ipaddr, sock->other_port,
- this)) {
-
-#ifdef HAVE_PTHREAD_H
- proxy_no_new_sockets = true;
-#endif
- PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
-
- /*
- * This is bad. However, the
- * packet list now supports 256
- * open sockets, which should
- * minimize this problem.
- */
- ERROR("Failed adding proxy socket: %s",
- fr_strerror());
- return 0;
- }
-
- if (sock->home) {
- sock->home->limit.num_connections++;
-
-#ifdef HAVE_PTHREAD_H
- /*
- * If necessary, add it to the list of
- * new proxy listeners.
- */
- if (sock->home->limit.lifetime || sock->home->limit.idle_timeout) {
- this->next = proxy_listener_list;
- proxy_listener_list = this;
- }
-#endif
- }
- PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
-
- /*
- * Tell the main thread that we've added
- * a proxy listener, but only if we need
- * to update the event list. Do this
- * with the mutex unlocked, to reduce
- * contention.
- */
- if (sock->home) {
- if (sock->home->limit.lifetime || sock->home->limit.idle_timeout) {
- radius_signal_self(RADIUS_SIGNAL_SELF_NEW_FD);
- }
- }
- }
-#endif
-
+ switch (this->type) {
#ifdef WITH_DETAIL
/*
* Detail files are always known, and aren't
* put into the socket event loop.
*/
- if (this->type == RAD_LISTEN_DETAIL) {
+ case RAD_LISTEN_DETAIL:
this->status = RAD_LISTEN_STATUS_KNOWN;
+#ifndef WITH_DETAIL_THREAD
/*
* Set up the first poll interval.
*/
event_poll_detail(this);
return 1;
- }
+#else
+ break; /* add the FD to the list */
#endif
+#endif /* WITH_DETAIL */
-#ifdef WITH_TCP
+#ifdef WITH_PROXY
/*
- * Add timers to child sockets, if necessary.
+ * Add it to the list of sockets we can use.
+ * Server sockets (i.e. auth/acct) are never
+ * added to the packet list.
*/
- if (sock->proto == IPPROTO_TCP && sock->opened &&
- (sock->limit.lifetime || sock->limit.idle_timeout)) {
- struct timeval when;
+ case RAD_LISTEN_PROXY:
+#ifdef WITH_TCP
+ /*
+ * Add timers to outgoing child sockets, if necessary.
+ */
+ if (sock->proto == IPPROTO_TCP && sock->opened &&
+ (sock->home->limit.lifetime || sock->home->limit.idle_timeout)) {
+ struct timeval when;
+
+ when.tv_sec = sock->opened + 1;
+ when.tv_usec = 0;
+
+ if (!fr_event_insert(el, tcp_socket_timer, this, &when,
+ &(sock->ev))) {
+ rad_panic("Failed to insert event");
+ }
+ }
+#endif
+ break;
+#endif /* WITH_PROXY */
- ASSERT_MASTER;
+ /*
+ * FIXME: put idle timers on command sockets.
+ */
- when.tv_sec = sock->opened + 1;
- when.tv_usec = 0;
+ default:
+#ifdef WITH_TCP
+ /*
+ * Add timers to incoming child sockets, if necessary.
+ */
+ if (sock->proto == IPPROTO_TCP && sock->opened &&
+ (sock->limit.lifetime || sock->limit.idle_timeout)) {
+ struct timeval when;
- if (!fr_event_insert(el, tcp_socket_timer, this, &when,
- &(sock->ev))) {
- rad_panic("Failed to insert event");
+ when.tv_sec = sock->opened + 1;
+ when.tv_usec = 0;
+
+ if (!fr_event_insert(el, tcp_socket_timer, this, &when,
+ &(sock->ev))) {
+ rad_panic("Failed to insert event");
+ }
}
- }
#endif
+ break;
+ } /* switch over listener types */
- FD_MUTEX_LOCK(&fd_mutex);
+ /*
+ * All sockets: add the FD to the event handler.
+ */
if (!fr_event_fd_insert(el, 0, this->fd,
event_socket_handler, this)) {
ERROR("Failed adding event handler for socket!");
fr_exit(1);
}
- FD_MUTEX_UNLOCK(&fd_mutex);
this->status = RAD_LISTEN_STATUS_KNOWN;
return 1;
* Stop using this socket, if at all possible.
*/
if (this->status == RAD_LISTEN_STATUS_EOL) {
+ /*
+ * Remove it from the list of live FD's.
+ */
+ fr_event_fd_delete(el, 0, this->fd);
+
#ifdef WITH_PROXY
/*
* Proxy sockets get frozen, so that we don't use
PTHREAD_MUTEX_LOCK(&proxy_mutex);
if (!fr_packet_list_socket_freeze(proxy_list,
this->fd)) {
- radlog(L_ERR, "Fatal error freezing socket: %s",
- fr_strerror());
+ ERROR("Fatal error freezing socket: %s", fr_strerror());
fr_exit(1);
}
+
+ fr_packet_list_walk(proxy_list, this, proxy_eol_cb);
PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
}
#endif
#ifdef WITH_TCP
listen_socket_t *sock = this->data;
#endif
-
- /*
- * Remove it from the list of live FD's.
- */
- FD_MUTEX_LOCK(&fd_mutex);
- fr_event_fd_delete(el, 0, this->fd);
- FD_MUTEX_UNLOCK(&fd_mutex);
+ struct timeval when;
/*
* Re-open the socket, pointing it to /dev/null.
devnull = open("/dev/null", O_RDWR);
if (devnull < 0) {
ERROR("FATAL failure opening /dev/null: %s",
- strerror(errno));
+ fr_syserror(errno));
fr_exit(1);
}
if (dup2(devnull, this->fd) < 0) {
ERROR("FATAL failure closing socket: %s",
- strerror(errno));
+ fr_syserror(errno));
fr_exit(1);
}
close(devnull);
#endif
#ifdef WITH_TCP
- INFO(" ... closing socket %s", buffer);
+ INFO(" ... shutting down socket %s", buffer);
#ifdef WITH_PROXY
/*
*/
if (this->type == RAD_LISTEN_PROXY) {
PTHREAD_MUTEX_LOCK(&proxy_mutex);
- fr_packet_list_walk(proxy_list, this,
- eol_proxy_listener);
+ fr_packet_list_walk(proxy_list, this, eol_proxy_listener);
if (!fr_packet_list_socket_del(proxy_list, this->fd)) {
ERROR("Fatal error removing socket %s: %s",
buffer, fr_strerror());
fr_exit(1);
}
- if (sock->home && sock->home->limit.num_connections) {
- sock->home->limit.num_connections--;
- }
PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
} else
#endif
/*
* EOL all requests using this socket.
*/
- fr_packet_list_walk(pl, this,
- eol_listener);
+ fr_packet_list_walk(pl, this, eol_listener);
}
/*
- * Remove any pending cleanups.
+ * No child threads, clean it up now.
*/
- if (sock->ev) fr_event_delete(el, &sock->ev);
+ if (!spawn_flag) {
+ if (sock->ev) fr_event_delete(el, &sock->ev);
+ listen_free(&this);
+ return 1;
+ }
/*
- * And finally, close the socket.
+ * Wait until all requests using this socket are done.
*/
- listen_free(&this);
+ gettimeofday(&when, NULL);
+ when.tv_sec += 3;
+
+ if (!fr_event_insert(el, listener_free_cb, this, &when,
+ &(sock->ev))) {
+ rad_panic("Failed to insert event");
+ }
}
#endif /* WITH_TCP */
static void handle_signal_self(int flag)
{
+ ASSERT_MASTER;
+
if ((flag & (RADIUS_SIGNAL_SELF_EXIT | RADIUS_SIGNAL_SELF_TERM)) != 0) {
if ((flag & RADIUS_SIGNAL_SELF_EXIT) != 0) {
INFO("Signalled to exit");
return;
}
- INFO("Received HUP signal.");
+ INFO("Received HUP signal");
last_hup = when;
}
#ifdef WITH_DETAIL
+#ifndef WITH_DETAIL_THREAD
if ((flag & RADIUS_SIGNAL_SELF_DETAIL) != 0) {
rad_listen_t *this;
/*
* FIXME: O(N) loops suck.
*/
- for (this = mainconfig.listen;
+ for (this = main_config.listen;
this != NULL;
this = this->next) {
if (this->type != RAD_LISTEN_DETAIL) continue;
}
}
#endif
+#endif
#ifdef WITH_TCP
#ifdef WITH_PROXY
#ifdef HAVE_PTHREAD_H
/*
- * Add event handlers for idle timeouts && maximum lifetime.
+ * There are new listeners in the list. Run
+ * event_new_fd() on them.
*/
if ((flag & RADIUS_SIGNAL_SELF_NEW_FD) != 0) {
- struct timeval when, now;
-
- fr_event_now(el, &now);
+ rad_listen_t *this, *next;
- PTHREAD_MUTEX_LOCK(&proxy_mutex);
-
- while (proxy_listener_list) {
- rad_listen_t *this = proxy_listener_list;
- listen_socket_t *sock = this->data;
+ FD_MUTEX_LOCK(&fd_mutex);
- rad_assert(sock->proto == IPPROTO_TCP);
- proxy_listener_list = this->next;
+ /*
+ * FIXME: unlock the mutex before calling
+ * event_new_fd()?
+ */
+ for (this = new_listeners; this != NULL; this = next) {
+ next = this->next;
this->next = NULL;
- if (!sock->home) continue; /* skip UDP sockets */
-
- when = now;
-
- /*
- * Sockets should only be added to the
- * proxy_listener_list if they have limits.
- *
- */
- rad_assert(sock->home->limit.lifetime || sock->home->limit.idle_timeout);
-
- if (!fr_event_insert(el, tcp_socket_timer, this, &when,
- &(sock->ev))) {
- rad_panic("Failed to insert event");
- }
+ event_new_fd(this);
}
- PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+ new_listeners = NULL;
+ FD_MUTEX_UNLOCK(&fd_mutex);
}
#endif /* HAVE_PTHREAD_H */
#endif /* WITH_PROXY */
#endif /* WITH_TCP */
}
-#ifndef WITH_SELF_PIPE
+#ifndef HAVE_PTHREAD_H
void radius_signal_self(int flag)
{
- handle_signal_self(flag);
+ return handle_signal_self(flag);
}
+
#else
+static int self_pipe[2] = { -1, -1 };
+
/*
* Inform ourselves that we received a signal.
*/
buffer[0] |= flag;
- write(self_pipe[1], buffer, 1);
+ if (write(self_pipe[1], buffer, 1) < 0) fr_exit(0);
}
handle_signal_self(buffer[0]);
}
-#endif
+#endif /* HAVE_PTHREAD_H */
/***********************************************************************
*
/*
* Externally-visibly functions.
*/
-int radius_event_init(CONF_SECTION *cs, int have_children)
+int radius_event_init(TALLOC_CTX *ctx) {
+ el = fr_event_list_create(ctx, event_status);
+ if (!el) return 0;
+
+ return 1;
+}
+
+int radius_event_start(CONF_SECTION *cs, bool have_children)
{
rad_listen_t *head = NULL;
- if (el) return 0;
+ if (fr_start_time != (time_t)-1) return 0;
time(&fr_start_time);
- el = fr_event_list_create(event_status);
- if (!el) return 0;
+ /*
+ * radius_event_init() must be called first
+ */
+ rad_assert(el);
+ if (fr_start_time == (time_t)-1) return 0;
pl = fr_packet_list_create(0);
if (!pl) return 0; /* leak el */
request_num_counter = 0;
#ifdef WITH_PROXY
- if (mainconfig.proxy_requests) {
+ if (main_config.proxy_requests) {
/*
* Create the tree for managing proxied requests and
* responses.
#ifdef HAVE_PTHREAD_H
if (pthread_mutex_init(&proxy_mutex, NULL) != 0) {
ERROR("FATAL: Failed to initialize proxy mutex: %s",
- strerror(errno));
+ fr_syserror(errno));
fr_exit(1);
}
#endif
}
#endif
+ /*
+ * Move all of the thread calls to this file?
+ *
+ * It may be best for the mutexes to be in this file...
+ */
+ spawn_flag = have_children;
+
#ifdef HAVE_PTHREAD_H
NO_SUCH_CHILD_PID = pthread_self(); /* not a child thread */
* we're running normally.
*/
if (have_children && !check_config &&
- (thread_pool_init(cs, &have_children) < 0)) {
+ (thread_pool_init(cs, &spawn_flag) < 0)) {
fr_exit(1);
}
#endif
- /*
- * Move all of the thread calls to this file?
- *
- * It may be best for the mutexes to be in this file...
- */
- spawn_flag = have_children;
-
if (check_config) {
DEBUG("%s: #### Skipping IP addresses and Ports ####",
- mainconfig.name);
+ main_config.name);
if (listen_init(cs, &head, spawn_flag) < 0) {
fflush(NULL);
fr_exit(1);
return 1;
}
-#ifdef WITH_SELF_PIPE
+#ifdef HAVE_PTHREAD_H
/*
* Child threads need a pipe to signal us, as do the
* signal handlers.
*/
if (pipe(self_pipe) < 0) {
ERROR("radiusd: Error opening internal pipe: %s",
- strerror(errno));
+ fr_syserror(errno));
fr_exit(1);
}
if ((fcntl(self_pipe[0], F_SETFL, O_NONBLOCK) < 0) ||
(fcntl(self_pipe[0], F_SETFD, FD_CLOEXEC) < 0)) {
ERROR("radiusd: Error setting internal flags: %s",
- strerror(errno));
+ fr_syserror(errno));
fr_exit(1);
}
if ((fcntl(self_pipe[1], F_SETFL, O_NONBLOCK) < 0) ||
(fcntl(self_pipe[1], F_SETFD, FD_CLOEXEC) < 0)) {
ERROR("radiusd: Error setting internal flags: %s",
- strerror(errno));
+ fr_syserror(errno));
fr_exit(1);
}
ERROR("Failed creating handler for signals");
fr_exit(1);
}
-#endif /* WITH_SELF_PIPE */
+#endif
DEBUG("%s: #### Opening IP addresses and Ports ####",
- mainconfig.name);
+ main_config.name);
/*
* The server temporarily switches to an unprivileged
fr_exit_now(1);
}
- mainconfig.listen = head;
+ main_config.listen = head;
/*
* At this point, no one has any business *ever* going
}
-static int request_hash_cb(UNUSED void *ctx, void *data)
+#ifdef WITH_PROXY
+static int proxy_delete_cb(UNUSED void *ctx, void *data)
{
- REQUEST *request = fr_packet2myptr(REQUEST, packet, data);
+ REQUEST *request = fr_packet2myptr(REQUEST, proxy, data);
-#ifdef WITH_PROXY
- rad_assert(request->in_proxy_hash == false);
+ request->master_state = REQUEST_STOP_PROCESSING;
+
+#ifdef HAVE_PTHREAD_H
+ if (pthread_equal(request->child_pid, NO_SUCH_CHILD_PID) == 0) return 0;
#endif
- request_done(request, FR_ACTION_DONE);
+ /*
+ * If it's queued we can't delete it from the queue.
+ *
+ * Otherwise, it's OK to delete it. Even RUNNING, because
+ * that will get caught by the check above.
+ */
+ if (request->child_state == REQUEST_QUEUED) return 0;
- return 0;
+ request->in_proxy_hash = false;
+
+ if (!request->in_request_hash) {
+ request_done(request, FR_ACTION_DONE);
+ }
+
+ /*
+ * Delete it from the list.
+ */
+ return 2;
}
+#endif
-#ifdef WITH_PROXY
-static int proxy_hash_cb(UNUSED void *ctx, void *data)
+static int request_delete_cb(UNUSED void *ctx, void *data)
{
- REQUEST *request = fr_packet2myptr(REQUEST, proxy, data);
+ REQUEST *request = fr_packet2myptr(REQUEST, packet, data);
- request_done(request, FR_ACTION_DONE);
+ request->master_state = REQUEST_STOP_PROCESSING;
- return 0;
-}
+ /*
+ * Not done, or the child thread is still processing it.
+ */
+ if (request->child_state < REQUEST_RESPONSE_DELAY) return 0; /* continue */
+
+#ifdef HAVE_PTHREAD_H
+ if (pthread_equal(request->child_pid, NO_SUCH_CHILD_PID) == 0) return 0;
#endif
-void radius_event_free(void)
-{
+#ifdef WITH_PROXY
+ rad_assert(request->in_proxy_hash == false);
+#endif
+
+ request->in_request_hash = false;
+ if (request->ev) fr_event_delete(el, &request->ev);
+
+ if (main_config.memory_report) {
+ RDEBUG2("Cleaning up request packet ID %u with timestamp +%d",
+ request->packet->id,
+ (unsigned int) (request->timestamp - fr_start_time));
+ }
+
+#ifdef WITH_COA
+ if (request->coa) {
+ rad_assert(!request->coa->in_proxy_hash);
+ }
+#endif
+
+ request_free(&request);
+
/*
- * Stop and join all threads.
+ * Delete it from the list, and continue;
*/
-#ifdef HAVE_PTHREAD_H
- thread_pool_stop();
+ return 2;
+}
+
+
+void radius_event_free(void)
+{
ASSERT_MASTER;
-#endif
#ifdef WITH_PROXY
/*
* referenced from anywhere else. Remove them first.
*/
if (proxy_list) {
- fr_packet_list_walk(proxy_list, NULL, proxy_hash_cb);
- fr_packet_list_free(proxy_list);
- proxy_list = NULL;
+ fr_packet_list_walk(proxy_list, NULL, proxy_delete_cb);
}
#endif
- fr_packet_list_walk(pl, NULL, request_hash_cb);
+ fr_packet_list_walk(pl, NULL, request_delete_cb);
+
+ if (spawn_flag) {
+ /*
+ * Now that all requests have been marked "please stop",
+ * ensure that all of the threads have exited.
+ */
+#ifdef HAVE_PTHREAD_H
+ thread_pool_stop();
+#endif
+
+ /*
+ * Walk the lists again, ensuring that all
+ * requests are done.
+ */
+ if (main_config.memory_report) {
+ int num;
+
+#ifdef WITH_PROXY
+ if (proxy_list) {
+ fr_packet_list_walk(proxy_list, NULL, proxy_delete_cb);
+ num = fr_packet_list_num_elements(proxy_list);
+ if (num > 0) {
+ ERROR("Proxy list has %d requests still in it.", num);
+ }
+ }
+#endif
+
+ fr_packet_list_walk(pl, NULL, request_delete_cb);
+ num = fr_packet_list_num_elements(pl);
+ if (num > 0) {
+ ERROR("Request list has %d requests still in it.", num);
+ }
+ }
+ }
fr_packet_list_free(pl);
pl = NULL;
- fr_event_list_free(el);
+#ifdef WITH_PROXY
+ fr_packet_list_free(proxy_list);
+ proxy_list = NULL;
+#endif
+
+ TALLOC_FREE(el);
+
+ if (debug_condition) talloc_free(debug_condition);
}
int radius_event_process(void)
{
ssize_t slen;
char const *error = NULL;
- char *fmt = talloc_strdup(NULL, input);
+ char *fmt = talloc_typed_strdup(NULL, input);
xlat_exp_t *head;
slen = xlat_tokenize(fmt, fmt, &head, &error);
if (strcmp(filename, "-") == 0) {
fp = stdin;
- filename = "<stdin>";
directory[0] = '\0';
} else {
fp = fopen(directory, "r");
if (!fp) {
fprintf(stderr, "Error opening %s: %s\n",
- directory, strerror(errno));
+ directory, fr_syserror(errno));
exit(1);
}
+
+ filename = directory;
}
lineno = 0;
while (isspace((int) *p)) p++;
if (!*p) continue;
+ DEBUG2("%s[%d]: %s\n", filename, lineno, buffer);
+
strlcpy(input, p, sizeof(input));
if (strncmp(p, "raw ", 4) == 0) {
continue;
}
+ if (outlen > sizeof(data)) outlen = sizeof(data);
+
+ if (outlen >= (sizeof(output) / 2)) {
+ outlen = (sizeof(output) / 2) - 1;
+ }
+
data_len = outlen;
for (i = 0; i < outlen; i++) {
- snprintf(output + 3*i, sizeof(output),
+ if (sizeof(output) < (3*i)) break;
+
+ snprintf(output + 3*i, sizeof(output) - (3*i) - 1,
"%02x ", data[i]);
}
outlen = strlen(output);
if (strncmp(p, "data ", 5) == 0) {
if (strcmp(p + 5, output) != 0) {
- fprintf(stderr, "Mismatch in line %d of %s, expected: %s\n",
- lineno, directory, output);
+ fprintf(stderr, "Mismatch in line %d of %s, got: %s expected: %s\n",
+ lineno, directory, output, p + 5);
exit(1);
}
continue;
if (head) {
vp_cursor_t cursor;
p = output;
- for (vp = paircursor(&cursor, &head);
+ for (vp = fr_cursor_init(&cursor, &head);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
vp_prints(p, sizeof(output) - (p - output), vp);
p += strlen(p);
continue;
}
+ if (strncmp(p, "attribute ", 10) == 0) {
+ p += 10;
+
+ if (userparse(NULL, p, &head) != T_EOL) {
+ strlcpy(output, fr_strerror(), sizeof(output));
+ continue;
+ }
+
+ vp_prints(output, sizeof(output), head);
+ continue;
+ }
+
if (strncmp(p, "$INCLUDE ", 9) == 0) {
char *q;
int main(int argc, char *argv[])
{
int c;
- int report = false;
+ bool report = false;
char const *radius_dir = RADDBDIR;
+ char const *dict_dir = DICTDIR;
- while ((c = getopt(argc, argv, "d:xM")) != EOF) switch(c) {
+#ifndef NDEBUG
+ if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
+ fr_perror("radattr");
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+ while ((c = getopt(argc, argv, "d:D:xM")) != EOF) switch(c) {
case 'd':
radius_dir = optarg;
break;
- case 'x':
+ case 'D':
+ dict_dir = optarg;
+ break;
+ case 'x':
fr_debug_flag++;
debug_flag = fr_debug_flag;
break;
argc -= (optind - 1);
argv += (optind - 1);
- if (report) {
- talloc_enable_null_tracking();
+ /*
+ * Mismatch between the binary and the libraries it depends on
+ */
+ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
+ fr_perror("radattr");
+ return 1;
+ }
+
+ if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) {
+ fr_perror("radattr");
+ return 1;
}
- talloc_set_log_fn(log_talloc);
- if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) {
+ if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) {
fr_perror("radattr");
return 1;
}
if (report) {
dict_free();
- log_talloc_report(NULL);
+ fr_log_talloc_report(NULL);
}
return 0;
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
- * Copyright 2000,2006 The FreeRADIUS server project
+ * Copyright 2000,2006,2014 The FreeRADIUS server project
* Copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl>
* Copyright 2000 Alan DeKok <aland@ox.org>
*/
RCSID("$Id$")
-#include <freeradius-devel/libradius.h>
-#include <freeradius-devel/conf.h>
+#include <freeradius-devel/radclient.h>
#include <freeradius-devel/radpaths.h>
-
+#include <freeradius-devel/conf.h>
#include <ctype.h>
#ifdef HAVE_GETOPT_H
-# include <getopt.h>
+# include <getopt.h>
#endif
#include <assert.h>
#include "smbdes.h"
#include "mschap.h"
-static int success = 0;
static int retries = 3;
static float timeout = 5;
static char const *secret = NULL;
-static int do_output = 1;
-static int totalapp = 0;
-static int totaldeny = 0;
-static int totallost = 0;
+static bool do_output = true;
+
+static rc_stats_t stats;
-static int server_port = 0;
+static uint16_t server_port = 0;
static int packet_code = 0;
static fr_ipaddr_t server_ipaddr;
static int resend_count = 1;
-static int done = 1;
-static int print_filename = 0;
+static bool done = true;
+static bool print_filename = false;
static fr_ipaddr_t client_ipaddr;
-static int client_port = 0;
+static uint16_t client_port = 0;
static int sockfd;
static int last_used_id = -1;
static int sleep_time = -1;
-typedef struct radclient_t {
- struct radclient_t *prev;
- struct radclient_t *next;
-
- char const *filename;
- int packet_number; /* in the file */
- char password[256];
- time_t timestamp;
- RADIUS_PACKET *request;
- RADIUS_PACKET *reply;
- int resend;
- int tries;
- int done;
-} radclient_t;
-
-static radclient_t *radclient_head = NULL;
-static radclient_t *radclient_tail = NULL;
+static rc_request_t *request_head = NULL;
+static rc_request_t *rc_request_tail = NULL;
char const *radclient_version = "radclient version " RADIUSD_VERSION_STRING
#ifdef RADIUSD_VERSION_COMMIT
-" (git #" RADIUSD_VERSION_COMMIT ")"
+" (git #" STRINGIFY(RADIUSD_VERSION_COMMIT) ")"
#endif
", built on " __DATE__ " at " __TIME__;
{
fprintf(stderr, "Usage: radclient [options] server[:port] <command> [<secret>]\n");
- fprintf(stderr, " <command> One of auth, acct, status, coa, or disconnect.\n");
- fprintf(stderr, " -c <count> Send each packet 'count' times.\n");
- fprintf(stderr, " -d <raddb> Set dictionary directory.\n");
- fprintf(stderr, " -f <file> Read packets from file, not stdin.\n");
- fprintf(stderr, " -F Print the file name, packet number and reply code.\n");
- fprintf(stderr, " -h Print usage help information.\n");
- fprintf(stderr, " -i <id> Set request id to 'id'. Values may be 0..255\n");
- fprintf(stderr, " -n <num> Send N requests/s\n");
- fprintf(stderr, " -p <num> Send 'num' packets from a file in parallel.\n");
- fprintf(stderr, " -q Do not print anything out.\n");
- fprintf(stderr, " -r <retries> If timeout, retry sending the packet 'retries' times.\n");
- fprintf(stderr, " -s Print out summary information of auth results.\n");
- fprintf(stderr, " -S <file> read secret from file, not command line.\n");
- fprintf(stderr, " -t <timeout> Wait 'timeout' seconds before retrying (may be a floating point number).\n");
- fprintf(stderr, " -v Show program version information.\n");
- fprintf(stderr, " -x Debugging mode.\n");
- fprintf(stderr, " -4 Use IPv4 address of server\n");
- fprintf(stderr, " -6 Use IPv6 address of server.\n");
+ fprintf(stderr, " <command> One of auth, acct, status, coa, or disconnect.\n");
+ fprintf(stderr, " -4 Use IPv4 address of server\n");
+ fprintf(stderr, " -6 Use IPv6 address of server.\n");
+ fprintf(stderr, " -c <count> Send each packet 'count' times.\n");
+ fprintf(stderr, " -d <raddb> Set user dictionary directory (defaults to " RADDBDIR ").\n");
+ fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
+ fprintf(stderr, " -f <file>[:<file>] Read packets from file, not stdin.\n");
+ fprintf(stderr, " If a second file is provided, it will be used to verify responses\n");
+ fprintf(stderr, " -F Print the file name, packet number and reply code.\n");
+ fprintf(stderr, " -h Print usage help information.\n");
+ fprintf(stderr, " -i <id> Set request id to 'id'. Values may be 0..255\n");
+ fprintf(stderr, " -n <num> Send N requests/s\n");
+ fprintf(stderr, " -p <num> Send 'num' packets from a file in parallel.\n");
+ fprintf(stderr, " -q Do not print anything out.\n");
+ fprintf(stderr, " -r <retries> If timeout, retry sending the packet 'retries' times.\n");
+ fprintf(stderr, " -s Print out summary information of auth results.\n");
+ fprintf(stderr, " -S <file> read secret from file, not command line.\n");
+ fprintf(stderr, " -t <timeout> Wait 'timeout' seconds before retrying (may be a floating point number).\n");
+ fprintf(stderr, " -v Show program version information.\n");
+ fprintf(stderr, " -x Debugging mode.\n");
+
#ifdef WITH_TCP
- fprintf(stderr, " -P <proto> Use proto (tcp or udp) for transport.\n");
+ fprintf(stderr, " -P <proto> Use proto (tcp or udp) for transport.\n");
#endif
exit(1);
}
+static const FR_NAME_NUMBER request_types[] = {
+ { "auth", PW_CODE_AUTHENTICATION_REQUEST },
+ { "challenge", PW_CODE_ACCESS_CHALLENGE },
+ { "acct", PW_CODE_ACCOUNTING_REQUEST },
+ { "status", PW_CODE_STATUS_SERVER },
+ { "disconnect", PW_CODE_DISCONNECT_REQUEST },
+ { "coa", PW_CODE_COA_REQUEST },
+ { "auto", PW_CODE_UNDEFINED },
+
+ { NULL, 0}
+};
+
/*
* Free a radclient struct, which may (or may not)
* already be in the list.
*/
-static void radclient_free(radclient_t *radclient)
+static int _rc_request_free(rc_request_t *request)
{
- radclient_t *prev, *next;
-
- if (radclient->request) rad_free(&radclient->request);
- if (radclient->reply) rad_free(&radclient->reply);
+ rc_request_t *prev, *next;
- prev = radclient->prev;
- next = radclient->next;
+ prev = request->prev;
+ next = request->next;
if (prev) {
- assert(radclient_head != radclient);
+ assert(request_head != request);
prev->next = next;
- } else if (radclient_head) {
- assert(radclient_head == radclient);
- radclient_head = next;
+ } else if (request_head) {
+ assert(request_head == request);
+ request_head = next;
}
if (next) {
- assert(radclient_tail != radclient);
+ assert(rc_request_tail != request);
next->prev = prev;
- } else if (radclient_tail) {
- assert(radclient_tail == radclient);
- radclient_tail = prev;
+ } else if (rc_request_tail) {
+ assert(rc_request_tail == request);
+ rc_request_tail = prev;
}
- free(radclient);
+ return 0;
}
static int mschapv1_encode(RADIUS_PACKET *packet, VALUE_PAIR **request,
{
unsigned int i;
uint8_t *p;
- VALUE_PAIR *challenge, *response;
+ VALUE_PAIR *challenge, *reply;
uint8_t nthash[16];
challenge = paircreate(packet, PW_MSCHAP_CHALLENGE, VENDORPEC_MICROSOFT);
p[i] = fr_rand();
}
- response = paircreate(packet, PW_MSCHAP_RESPONSE, VENDORPEC_MICROSOFT);
- if (!response) {
+ reply = paircreate(packet, PW_MSCHAP_RESPONSE, VENDORPEC_MICROSOFT);
+ if (!reply) {
return 0;
}
- pairadd(request, response);
- response->length = 50;
- response->vp_octets = p = talloc_array(response, uint8_t, response->length);
- memset(p, 0, response->length);
+ pairadd(request, reply);
+ reply->length = 50;
+ reply->vp_octets = p = talloc_array(reply, uint8_t, reply->length);
+ memset(p, 0, reply->length);
p[1] = 0x01; /* NT hash */
}
+static int getport(char const *name)
+{
+ struct servent *svp;
+
+ svp = getservbyname(name, "udp");
+ if (!svp) {
+ return 0;
+ }
+
+ return ntohs(svp->s_port);
+}
+
+static void radclient_get_port(PW_CODE type, uint16_t *port)
+{
+ switch (type) {
+ default:
+ case PW_CODE_AUTHENTICATION_REQUEST:
+ case PW_CODE_ACCESS_CHALLENGE:
+ case PW_CODE_STATUS_SERVER:
+ if (*port == 0) *port = getport("radius");
+ if (*port == 0) *port = PW_AUTH_UDP_PORT;
+ return;
+
+ case PW_CODE_ACCOUNTING_REQUEST:
+ if (*port == 0) *port = getport("radacct");
+ if (*port == 0) *port = PW_ACCT_UDP_PORT;
+ return;
+
+ case PW_CODE_DISCONNECT_REQUEST:
+ case PW_CODE_COA_REQUEST:
+ if (*port == 0) *port = PW_COA_UDP_PORT;
+ return;
+
+ case PW_CODE_UNDEFINED:
+ if (*port == 0) *port = 0;
+ }
+}
+
/*
* Initialize a radclient data structure and add it to
* the global linked list.
*/
-static int radclient_init(char const *filename)
+static int radclient_init(TALLOC_CTX *ctx, rc_file_pair_t *files)
{
- FILE *fp;
+ FILE *packets, *filters = NULL;
+
vp_cursor_t cursor;
VALUE_PAIR *vp;
- radclient_t *radclient;
- int filedone = 0;
- int packet_number = 1;
+ rc_request_t *request;
+ bool packets_done = false;
+ uint64_t num = 0;
- assert(filename != NULL);
+ assert(files->packets != NULL);
/*
* Determine where to read the VP's from.
*/
- if (strcmp(filename, "-") != 0) {
- fp = fopen(filename, "r");
- if (!fp) {
- fprintf(stderr, "radclient: Error opening %s: %s\n",
- filename, strerror(errno));
+ if (strcmp(files->packets, "-") != 0) {
+ packets = fopen(files->packets, "r");
+ if (!packets) {
+ ERROR("Error opening %s: %s", files->packets, strerror(errno));
return 0;
}
+
+ /*
+ * Read in the pairs representing the expected response.
+ */
+ if (files->filters) {
+ filters = fopen(files->filters, "r");
+ if (!filters) {
+ ERROR("Error opening %s: %s", files->filters, strerror(errno));
+ fclose(packets);
+ return 0;
+ }
+ }
} else {
- fp = stdin;
+ packets = stdin;
}
+
/*
* Loop until the file is done.
*/
/*
* Allocate it.
*/
- radclient = malloc(sizeof(*radclient));
- if (!radclient) {
- goto oom;
+ request = talloc_zero(ctx, rc_request_t);
+ if (!request) {
+ ERROR("Out of memory");
+ goto error;
}
- memset(radclient, 0, sizeof(*radclient));
+ talloc_set_destructor(request, _rc_request_free);
- radclient->request = rad_alloc(NULL, 1);
- if (!radclient->request) {
- goto oom;
+ request->packet = rad_alloc(request, 1);
+ if (!request->packet) {
+ ERROR("Out of memory");
+ goto error;
}
#ifdef WITH_TCP
- radclient->request->src_ipaddr = client_ipaddr;
- radclient->request->src_port = client_port;
- radclient->request->dst_ipaddr = server_ipaddr;
- radclient->request->dst_port = server_port;
+ request->packet->src_ipaddr = client_ipaddr;
+ request->packet->src_port = client_port;
+ request->packet->dst_ipaddr = server_ipaddr;
+ request->packet->dst_port = server_port;
+ request->packet->proto = ipproto;
#endif
- radclient->filename = filename;
- radclient->request->id = -1; /* allocate when sending */
- radclient->packet_number = packet_number++;
+ request->files = files;
+ request->packet->id = -1; /* allocate when sending */
+ request->num = num++;
/*
- * Read the VP's.
+ * Read the request VP's.
*/
- radclient->request->vps = readvp2(NULL, fp, &filedone, "radclient:");
- if (!radclient->request->vps) {
- rad_free(&radclient->request);
- free(radclient);
- if (fp != stdin) fclose(fp);
- return 1;
+ if (readvp2(&request->packet->vps, request->packet, packets, &packets_done) < 0) {
+ ERROR("Error parsing \"%s\"", files->packets);
+ goto error;
+ }
+
+ fr_cursor_init(&cursor, &request->filter);
+ vp = fr_cursor_next_by_num(&cursor, PW_PACKET_TYPE, 0, TAG_ANY);
+ if (vp) {
+ fr_cursor_remove(&cursor);
+ request->packet_code = vp->vp_integer;
+ talloc_free(vp);
+ } else {
+ request->packet_code = packet_code; /* Use the default set on the command line */
}
/*
- * Keep a copy of the the User-Password attribute.
+ * Read in filter VP's.
*/
- if ((vp = pairfind(radclient->request->vps, PW_USER_PASSWORD, 0, TAG_ANY)) != NULL) {
- strlcpy(radclient->password, vp->vp_strvalue,
- sizeof(radclient->password));
+ if (filters) {
+ bool filters_done;
+
+ if (readvp2(&request->filter, request, filters, &filters_done) < 0) {
+ ERROR("Error parsing \"%s\"", files->filters);
+ goto error;
+ }
+
+ if (!request->filter) {
+ goto error;
+ }
+
+ if (filters_done && !packets_done) {
+ ERROR("Differing number of packets/filters in %s:%s "
+ "(too many requests))", files->packets, files->filters);
+ goto error;
+ }
+
+ if (!filters_done && packets_done) {
+ ERROR("Differing number of packets/filters in %s:%s "
+ "(too many filters))", files->packets, files->filters);
+ goto error;
+ }
+
+ fr_cursor_init(&cursor, &request->filter);
+ vp = fr_cursor_next_by_num(&cursor, PW_PACKET_TYPE, 0, TAG_ANY);
+ if (vp) {
+ fr_cursor_remove(&cursor);
+ request->filter_code = vp->vp_integer;
+ talloc_free(vp);
+ }
+
/*
- * Otherwise keep a copy of the CHAP-Password attribute.
+ * xlat expansions aren't supported here
*/
- } else if ((vp = pairfind(radclient->request->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) != NULL) {
- strlcpy(radclient->password, vp->vp_strvalue,
- sizeof(radclient->password));
+ for (vp = fr_cursor_init(&cursor, &request->filter);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ if (vp->type == VT_XLAT) {
+ vp->type = VT_DATA;
+ vp->vp_strvalue = vp->value.xlat;
+ }
+ }
+
+ /*
+ * This allows efficient list comparisons later
+ */
+ pairsort(&request->filter, attrtagcmp);
+ }
+
+ /*
+ * Determine the response code from the request (if not already set)
+ */
+ if (!request->filter_code) {
+ switch (request->packet_code) {
+ case PW_CODE_AUTHENTICATION_REQUEST:
+ request->filter_code = PW_CODE_AUTHENTICATION_ACK;
+ break;
+
+ case PW_CODE_ACCOUNTING_REQUEST:
+ request->filter_code = PW_CODE_ACCOUNTING_RESPONSE;
+ break;
+
+ case PW_CODE_COA_REQUEST:
+ request->filter_code = PW_CODE_COA_ACK;
+ break;
+
+ case PW_CODE_DISCONNECT_REQUEST:
+ request->filter_code = PW_CODE_DISCONNECT_ACK;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /*
+ * Keep a copy of the the User-Password attribute.
+ */
+ if ((vp = pairfind(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY)) != NULL) {
+ strlcpy(request->password, vp->vp_strvalue,
+ sizeof(request->password));
+ /*
+ * Otherwise keep a copy of the CHAP-Password attribute.
+ */
+ } else if ((vp = pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) != NULL) {
+ strlcpy(request->password, vp->vp_strvalue,
+ sizeof(request->password));
- } else if ((vp = pairfind(radclient->request->vps, PW_MSCHAP_PASSWORD, 0, TAG_ANY)) != NULL) {
- strlcpy(radclient->password, vp->vp_strvalue,
- sizeof(radclient->password));
+ } else if ((vp = pairfind(request->packet->vps, PW_MS_CHAP_PASSWORD, 0, TAG_ANY)) != NULL) {
+ strlcpy(request->password, vp->vp_strvalue,
+ sizeof(request->password));
} else {
- radclient->password[0] = '\0';
+ request->password[0] = '\0';
}
/*
* Fix up Digest-Attributes issues
*/
- for (vp = paircursor(&cursor, &radclient->request->vps);
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
vp;
- vp = pairnext(&cursor)) {
- /*
- * Double quoted strings get marked up as xlat expansions,
- * but we don't support that in radclient.
- */
+ vp = fr_cursor_next(&cursor)) {
+ /*
+ * Double quoted strings get marked up as xlat expansions,
+ * but we don't support that in request.
+ */
if (vp->type == VT_XLAT) {
vp->vp_strvalue = vp->value.xlat;
vp->value.xlat = NULL;
* the attributes read from the file.
*/
case PW_PACKET_TYPE:
- radclient->request->code = vp->vp_integer;
+ request->packet->code = vp->vp_integer;
break;
case PW_PACKET_DST_PORT:
- radclient->request->dst_port = (vp->vp_integer & 0xffff);
+ request->packet->dst_port = (vp->vp_integer & 0xffff);
break;
case PW_PACKET_DST_IP_ADDRESS:
- radclient->request->dst_ipaddr.af = AF_INET;
- radclient->request->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ request->packet->dst_ipaddr.af = AF_INET;
+ request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
break;
case PW_PACKET_DST_IPV6_ADDRESS:
- radclient->request->dst_ipaddr.af = AF_INET6;
- radclient->request->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
+ request->packet->dst_ipaddr.af = AF_INET6;
+ request->packet->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
break;
case PW_PACKET_SRC_PORT:
- radclient->request->src_port = (vp->vp_integer & 0xffff);
+ request->packet->src_port = (vp->vp_integer & 0xffff);
break;
case PW_PACKET_SRC_IP_ADDRESS:
- radclient->request->src_ipaddr.af = AF_INET;
- radclient->request->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ request->packet->src_ipaddr.af = AF_INET;
+ request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
break;
case PW_PACKET_SRC_IPV6_ADDRESS:
- radclient->request->src_ipaddr.af = AF_INET6;
- radclient->request->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
+ request->packet->src_ipaddr.af = AF_INET6;
+ request->packet->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
break;
case PW_DIGEST_REALM:
/* overlapping! */
{
DICT_ATTR const *da;
- uint8_t *p;
+ uint8_t *p, *q;
p = talloc_array(vp, uint8_t, vp->length + 2);
vp->length += 2;
p[1] = vp->length;
- pairmemsteal(vp, p);
-
da = dict_attrbyvalue(PW_DIGEST_ATTRIBUTES, 0);
if (!da) {
- goto oom;
+ ERROR("Out of memory");
+ goto error;
}
-
vp->da = da;
+
+ /*
+ * Re-do pairmemsteal ourselves,
+ * because we play games with
+ * vp->da, and pairmemsteal goes
+ * to GREAT lengths to sanitize
+ * and fix and change and
+ * double-check the various
+ * fields.
+ */
+ memcpy(&q, &vp->vp_octets, sizeof(q));
+ talloc_free(q);
+
+ vp->vp_octets = talloc_steal(vp, p);
+ vp->type = VT_DATA;
+
+ VERIFY_VP(vp);
}
break;
} /* loop over the VP's we read in */
/*
+ * Automatically set the port if we don't have a global
+ * or packet specific one.
+ */
+ if ((server_port == 0) && (request->packet->dst_port == 0)) {
+ radclient_get_port(request->packet->code, &request->packet->dst_port);
+ }
+
+ /*
* Add it to the tail of the list.
*/
- if (!radclient_head) {
- assert(radclient_tail == NULL);
- radclient_head = radclient;
- radclient->prev = NULL;
+ if (!request_head) {
+ assert(rc_request_tail == NULL);
+ request_head = request;
+ request->prev = NULL;
} else {
- assert(radclient_tail->next == NULL);
- radclient_tail->next = radclient;
- radclient->prev = radclient_tail;
+ assert(rc_request_tail->next == NULL);
+ rc_request_tail->next = request;
+ request->prev = rc_request_tail;
}
- radclient_tail = radclient;
- radclient->next = NULL;
+ rc_request_tail = request;
+ request->next = NULL;
- } while (!filedone); /* loop until the file is done. */
+ } while (!packets_done); /* loop until the file is done. */
- if (fp != stdin) fclose(fp);
+ if (packets != stdin) fclose(packets);
+ if (filters) fclose(filters);
/*
* And we're done.
*/
return 1;
- oom:
- fprintf(stderr, "radclient: Out of memory\n");
- free(radclient);
- if (fp != stdin) fclose(fp);
+error:
+ talloc_free(request);
+
+ if (packets != stdin) fclose(packets);
+ if (filters) fclose(filters);
+
return 0;
}
/*
* Sanity check each argument.
*/
-static int radclient_sane(radclient_t *radclient)
+static int radclient_sane(rc_request_t *request)
{
- if (radclient->request->dst_port == 0) {
- radclient->request->dst_port = server_port;
+ if (request->packet->dst_port == 0) {
+ request->packet->dst_port = server_port;
}
- if (radclient->request->dst_ipaddr.af == AF_UNSPEC) {
+ if (request->packet->dst_ipaddr.af == AF_UNSPEC) {
if (server_ipaddr.af == AF_UNSPEC) {
- fprintf(stderr, "radclient: No server was given, but request %d in file %s did not contain Packet-Dst-IP-Address\n",
- radclient->packet_number, radclient->filename);
+ ERROR("No server was given, and request %" PRIu64 " in file %s did not contain "
+ "Packet-Dst-IP-Address", request->num, request->files->packets);
return -1;
}
- radclient->request->dst_ipaddr = server_ipaddr;
+ request->packet->dst_ipaddr = server_ipaddr;
}
- if (radclient->request->code == 0) {
+ if (request->packet->code == 0) {
if (packet_code == -1) {
- fprintf(stderr, "radclient: Request was \"auto\", but request %d in file %s did not contain Packet-Type\n",
- radclient->packet_number, radclient->filename);
+ ERROR("Request was \"auto\", and request %" PRIu64 " in file %s did not contain Packet-Type",
+ request->num, request->files->packets);
return -1;
}
- radclient->request->code = packet_code;
+ request->packet->code = packet_code;
}
- radclient->request->sockfd = -1;
+ request->packet->sockfd = -1;
return 0;
}
/*
- * For request handline.
+ * For request handling.
*/
static int filename_cmp(void const *one, void const *two)
{
- return strcmp((char const *) one, (char const *) two);
+ int cmp;
+
+ rc_file_pair_t const *a = one;
+ rc_file_pair_t const *b = two;
+
+ cmp = strcmp(a->packets, b->packets);
+ if (cmp != 0) return cmp;
+
+ return strcmp(a->filters, b->filters);
}
static int filename_walk(UNUSED void *context, void *data)
{
- char const *filename = data;
+ rc_file_pair_t *files = data;
/*
* Read request(s) from the file.
*/
- if (!radclient_init(filename)) {
+ if (!radclient_init(files, files)) {
return -1; /* stop walking */
}
/*
* Deallocate packet ID, etc.
*/
-static void deallocate_id(radclient_t *radclient)
+static void deallocate_id(rc_request_t *request)
{
- if (!radclient || !radclient->request ||
- (radclient->request->id < 0)) {
+ if (!request || !request->packet ||
+ (request->packet->id < 0)) {
return;
}
/*
* One more unused RADIUS ID.
*/
- fr_packet_list_id_free(pl, radclient->request, true);
+ fr_packet_list_id_free(pl, request->packet, true);
/*
* If we've already sent a packet, free up the old one,
* and ensure that the next packet has a unique
* authentication vector.
*/
- if (radclient->request->data) {
- talloc_free(radclient->request->data);
- radclient->request->data = NULL;
+ if (request->packet->data) {
+ TALLOC_FREE(request->packet->data);
}
- if (radclient->reply) rad_free(&radclient->reply);
-}
-
-
-static void print_hex(RADIUS_PACKET *packet)
-{
- int i;
-
- if (!packet->data) return;
-
- printf(" Code:\t\t%u\n", packet->data[0]);
- printf(" Id:\t\t%u\n", packet->data[1]);
- printf(" Length:\t%u\n", ((packet->data[2] << 8) |
- (packet->data[3])));
- printf(" Vector:\t");
- for (i = 4; i < 20; i++) {
- printf("%02x", packet->data[i]);
- }
- printf("\n");
-
- if (packet->data_len > 20) {
- int total;
- uint8_t const *ptr;
- printf(" Data:");
-
- total = packet->data_len - 20;
- ptr = packet->data + 20;
-
- while (total > 0) {
- int attrlen;
-
- printf("\t\t");
- if (total < 2) { /* too short */
- printf("%02x\n", *ptr);
- break;
- }
-
- if (ptr[1] > total) { /* too long */
- for (i = 0; i < total; i++) {
- printf("%02x ", ptr[i]);
- }
- break;
- }
-
- printf("%02x %02x ", ptr[0], ptr[1]);
- attrlen = ptr[1] - 2;
- ptr += 2;
- total -= 2;
-
- for (i = 0; i < attrlen; i++) {
- if ((i > 0) && ((i & 0x0f) == 0x00))
- printf("\t\t\t");
- printf("%02x ", ptr[i]);
- if ((i & 0x0f) == 0x0f) printf("\n");
- }
-
- if ((attrlen & 0x0f) != 0x00) printf("\n");
-
- ptr += attrlen;
- total -= attrlen;
- }
- }
- fflush(stdout);
+ if (request->reply) rad_free(&request->reply);
}
/*
* Send one packet.
*/
-static int send_one_packet(radclient_t *radclient)
+static int send_one_packet(rc_request_t *request)
{
- assert(radclient->done == 0);
+ assert(request->done == false);
/*
* Remember when we have to wake up, to re-send the
- * request, of we didn't receive a response.
+ * request, of we didn't receive a reply.
*/
- if ((sleep_time == -1) ||
- (sleep_time > (int) timeout)) {
+ if ((sleep_time == -1) || (sleep_time > (int) timeout)) {
sleep_time = (int) timeout;
}
/*
* Haven't sent the packet yet. Initialize it.
*/
- if (radclient->request->id == -1) {
+ if (request->packet->id == -1) {
int i;
bool rcode;
- assert(radclient->reply == NULL);
+ assert(request->reply == NULL);
/*
* Didn't find a free packet ID, we're not done,
* this packet.
*/
retry:
- radclient->request->src_ipaddr.af = server_ipaddr.af;
+ request->packet->src_ipaddr.af = server_ipaddr.af;
rcode = fr_packet_list_id_alloc(pl, ipproto,
- &radclient->request, NULL);
+ &request->packet, NULL);
if (!rcode) {
int mysockfd;
#endif
mysockfd = fr_socket(&client_ipaddr, 0);
if (mysockfd < 0) {
- fprintf(stderr, "radclient: Can't open new socket: %s\n",
- strerror(errno));
+ ERROR("Can't open new socket: %s", strerror(errno));
exit(1);
}
if (!fr_packet_list_socket_add(pl, mysockfd, ipproto,
&server_ipaddr,
server_port, NULL)) {
- fprintf(stderr, "radclient: Can't add new socket\n");
+ ERROR("Can't add new socket");
exit(1);
}
goto retry;
}
- assert(radclient->request->id != -1);
- assert(radclient->request->data == NULL);
+ assert(request->packet->id != -1);
+ assert(request->packet->data == NULL);
for (i = 0; i < 4; i++) {
- ((uint32_t *) radclient->request->vector)[i] = fr_rand();
+ ((uint32_t *) request->packet->vector)[i] = fr_rand();
}
/*
* Update the password, so it can be encrypted with the
* new authentication vector.
*/
- if (radclient->password[0] != '\0') {
+ if (request->password[0] != '\0') {
VALUE_PAIR *vp;
- if ((vp = pairfind(radclient->request->vps, PW_USER_PASSWORD, 0, TAG_ANY)) != NULL) {
- pairstrcpy(vp, radclient->password);
+ if ((vp = pairfind(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY)) != NULL) {
+ pairstrcpy(vp, request->password);
- } else if ((vp = pairfind(radclient->request->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) != NULL) {
- int already_hex = 0;
+ } else if ((vp = pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) != NULL) {
+ bool already_hex = false;
/*
* If it's 17 octets, it *might* be already encoded.
if (vp->length == 17) {
for (i = 0; i < 17; i++) {
if (vp->vp_octets[i] < 32) {
- already_hex = 1;
+ already_hex = true;
break;
}
}
uint8_t *p;
size_t len, len2;
- len = len2 = strlen(radclient->password);
+ len = len2 = strlen(request->password);
if (len2 < 17) len2 = 17;
p = talloc_zero_array(vp, uint8_t, len2);
- memcpy(p, radclient->password, len);
+ memcpy(p, request->password, len);
- rad_chap_encode(radclient->request,
+ rad_chap_encode(request->packet,
p,
fr_rand() & 0xff, vp);
vp->vp_octets = p;
vp->length = 17;
}
- } else if (pairfind(radclient->request->vps, PW_MSCHAP_PASSWORD, 0, TAG_ANY) != NULL) {
- mschapv1_encode(radclient->request,
- &radclient->request->vps,
- radclient->password);
- } else if (fr_debug_flag) {
- printf("WARNING: No password in the request\n");
+ } else if (pairfind(request->packet->vps, PW_MS_CHAP_PASSWORD, 0, TAG_ANY) != NULL) {
+ mschapv1_encode(request->packet,
+ &request->packet->vps,
+ request->password);
+ } else {
+ DEBUG("WARNING: No password in the request");
}
}
- radclient->timestamp = time(NULL);
- radclient->tries = 1;
- radclient->resend++;
+ request->timestamp = time(NULL);
+ request->tries = 1;
+ request->resend++;
#ifdef WITH_TCP
/*
* WTF?
*/
if (client_port == 0) {
- client_ipaddr = radclient->request->src_ipaddr;
- client_port = radclient->request->src_port;
+ client_ipaddr = request->packet->src_ipaddr;
+ client_port = request->packet->src_port;
}
#endif
- } else { /* radclient->request->id >= 0 */
+ } else { /* request->packet->id >= 0 */
time_t now = time(NULL);
/*
/*
* Not time for a retry, do so.
*/
- if ((now - radclient->timestamp) < timeout) {
+ if ((now - request->timestamp) < timeout) {
/*
* When we walk over the tree sending
* packets, we update the minimum time
* required to sleep.
*/
if ((sleep_time == -1) ||
- (sleep_time > (now - radclient->timestamp))) {
- sleep_time = now - radclient->timestamp;
+ (sleep_time > (now - request->timestamp))) {
+ sleep_time = now - request->timestamp;
}
return 0;
}
/*
* We're not trying later, maybe the packet is done.
*/
- if (radclient->tries == retries) {
- assert(radclient->request->id >= 0);
+ if (request->tries == retries) {
+ assert(request->packet->id >= 0);
/*
* Delete the request from the tree of
* outstanding requests.
*/
- fr_packet_list_yank(pl, radclient->request);
+ fr_packet_list_yank(pl, request->packet);
- fprintf(stderr, "radclient: no response from server for ID %d socket %d\n", radclient->request->id, radclient->request->sockfd);
- deallocate_id(radclient);
+ REDEBUG("No reply from server for ID %d socket %d",
+ request->packet->id, request->packet->sockfd);
+ deallocate_id(request);
/*
* Normally we mark it "done" when we've received
- * the response, but this is a special case.
+ * the reply, but this is a special case.
*/
- if (radclient->resend == resend_count) {
- radclient->done = 1;
+ if (request->resend == resend_count) {
+ request->done = true;
}
- totallost++;
+ stats.lost++;
return -1;
}
/*
* We are trying later.
*/
- radclient->timestamp = now;
- radclient->tries++;
+ request->timestamp = now;
+ request->tries++;
}
-
/*
* Send the packet.
*/
- if (rad_send(radclient->request, NULL, secret) < 0) {
- fprintf(stderr, "radclient: Failed to send packet for ID %d: %s\n",
- radclient->request->id, fr_strerror());
+ if (rad_send(request->packet, NULL, secret) < 0) {
+ REDEBUG("Failed to send packet for ID %d", request->packet->id);
}
- if (fr_debug_flag > 2) print_hex(radclient->request);
-
return 0;
}
{
fd_set set;
struct timeval tv;
- radclient_t *radclient;
- RADIUS_PACKET *reply, **request_p;
+ rc_request_t *request;
+ RADIUS_PACKET *reply, **packet_p;
volatile int max_fd;
/* And wait for reply, timing out as necessary */
/*
* Look for the packet.
*/
-
reply = fr_packet_list_recv(pl, &set);
if (!reply) {
- fprintf(stderr, "radclient: received bad packet: %s\n",
- fr_strerror());
+ ERROR("Received bad packet");
#ifdef WITH_TCP
/*
* If the packet is bad, we close the socket.
reply->src_port = server_port;
#endif
- if (fr_debug_flag > 2) print_hex(reply);
-
- request_p = fr_packet_list_find_byreply(pl, reply);
- if (!request_p) {
- fprintf(stderr, "radclient: received response to request we did not send. (id=%d socket %d)\n", reply->id, reply->sockfd);
+ packet_p = fr_packet_list_find_byreply(pl, reply);
+ if (!packet_p) {
+ ERROR("Received reply to request we did not send. (id=%d socket %d)",
+ reply->id, reply->sockfd);
rad_free(&reply);
return -1; /* got reply to packet we didn't send */
}
- radclient = fr_packet2myptr(radclient_t, request, request_p);
+ request = fr_packet2myptr(rc_request_t, packet, packet_p);
/*
* Fails the signature validation: not a real reply.
* FIXME: Silently drop it and listen for another packet.
*/
- if (rad_verify(reply, radclient->request, secret) < 0) {
- fr_perror("rad_verify");
- totallost++;
+ if (rad_verify(reply, request->packet, secret) < 0) {
+ REDEBUG("Reply verification failed");
+ stats.lost++;
goto packet_done; /* shared secret is incorrect */
}
- if (print_filename) printf("%s:%d %d\n",
- radclient->filename,
- radclient->packet_number,
- reply->code);
- deallocate_id(radclient);
- radclient->reply = reply;
+ if (print_filename) {
+ RDEBUG("%s response code %d", request->files->packets, reply->code);
+ }
+
+ deallocate_id(request);
+ request->reply = reply;
reply = NULL;
/*
* If this fails, we're out of memory.
*/
- if (rad_decode(radclient->reply, radclient->request, secret) != 0) {
- fr_perror("rad_decode");
- totallost++;
+ if (rad_decode(request->reply, request->packet, secret) != 0) {
+ REDEBUG("Reply decode failed");
+ stats.lost++;
goto packet_done;
}
- /* libradius debug already prints out the value pairs for us */
- if (!fr_debug_flag && do_output) {
- printf("Received response ID %d, code %d, length = %zd\n",
- radclient->reply->id, radclient->reply->code,
- radclient->reply->data_len);
- vp_printlist(stdout, radclient->reply->vps);
+ /*
+ * Increment counters...
+ */
+ switch (request->reply->code) {
+ case PW_CODE_AUTHENTICATION_ACK:
+ case PW_CODE_ACCOUNTING_RESPONSE:
+ case PW_CODE_COA_ACK:
+ case PW_CODE_DISCONNECT_ACK:
+ stats.accepted++;
+ break;
+
+ case PW_CODE_ACCESS_CHALLENGE:
+ break;
+
+ default:
+ stats.rejected++;
}
- if ((radclient->reply->code == PW_AUTHENTICATION_ACK) ||
- (radclient->reply->code == PW_ACCOUNTING_RESPONSE) ||
- (radclient->reply->code == PW_COA_ACK) ||
- (radclient->reply->code == PW_DISCONNECT_ACK)) {
- success = 1; /* have a good response */
- totalapp++;
+ /*
+ * If we had an expected response code, check to see if the
+ * packet matched that.
+ */
+ if (request->reply->code != request->filter_code) {
+ if (is_radius_code(request->packet_code)) {
+ REDEBUG("Expected %s got %s", fr_packet_codes[request->filter_code],
+ fr_packet_codes[request->reply->code]);
+ } else {
+ REDEBUG("Expected %u got %i", request->filter_code,
+ request->reply->code);
+ }
+ stats.failed++;
+ /*
+ * Check if the contents of the packet matched the filter
+ */
+ } else if (!request->filter) {
+ stats.passed++;
} else {
- totaldeny++;
+ VALUE_PAIR const *failed[2];
+
+ pairsort(&request->reply->vps, attrtagcmp);
+ if (pairvalidate(failed, request->filter, request->reply->vps)) {
+ RDEBUG("Response passed filter");
+ stats.passed++;
+ } else {
+ pairvalidate_debug(request, failed);
+ REDEBUG("Response failed filter");
+ stats.failed++;
+ }
}
- if (radclient->resend == resend_count) {
- radclient->done = 1;
+ if (request->resend == resend_count) {
+ request->done = true;
}
- packet_done:
- rad_free(&radclient->reply);
+packet_done:
+ rad_free(&request->reply);
rad_free(&reply); /* may be NULL */
return 0;
}
-
-static int getport(char const *name)
-{
- struct servent *svp;
-
- svp = getservbyname (name, "udp");
- if (!svp) {
- return 0;
- }
-
- return ntohs(svp->s_port);
-}
-
int main(int argc, char **argv)
{
- char *p;
int c;
char const *radius_dir = RADDBDIR;
+ char const *dict_dir = DICTDIR;
char filesecret[256];
FILE *fp;
- int do_summary = 0;
+ int do_summary = false;
int persec = 0;
int parallel = 1;
- radclient_t *this;
+ rc_request_t *this;
int force_af = AF_UNSPEC;
- fr_debug_flag = 0;
+ fr_debug_flag = 2;
+ fr_log_fp = stdout;
+
+#ifndef NDEBUG
+ if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
+ fr_perror("radclient");
+ exit(EXIT_FAILURE);
+ }
+#endif
talloc_set_log_stderr();
filename_tree = rbtree_create(filename_cmp, NULL, 0);
if (!filename_tree) {
- fprintf(stderr, "radclient: Out of memory\n");
+ oom:
+ ERROR("Out of memory");
exit(1);
}
- while ((c = getopt(argc, argv, "46c:d:f:Fhi:n:p:qr:sS:t:vx"
+ while ((c = getopt(argc, argv, "46c:d:D:f:Fhi:n:p:qr:sS:t:vx"
#ifdef WITH_TCP
"P:"
#endif
usage();
resend_count = atoi(optarg);
break;
+ case 'D':
+ dict_dir = optarg;
+ break;
case 'd':
radius_dir = optarg;
break;
case 'f':
- rbtree_insert(filename_tree, optarg);
+ {
+ char const *p;
+ rc_file_pair_t *files;
+
+ files = talloc(talloc_autofree_context(), rc_file_pair_t);
+ if (!files) goto oom;
+
+ p = strchr(optarg, ':');
+ if (p) {
+ files->packets = talloc_strndup(files, optarg, p - optarg);
+ if (!files->packets) goto oom;
+ files->filters = p + 1;
+ } else {
+ files->packets = optarg;
+ files->filters = NULL;
+ }
+ rbtree_insert(filename_tree, (void *) files);
+ }
break;
case 'F':
- print_filename = 1;
+ print_filename = true;
break;
case 'i': /* currently broken */
if (!isdigit((int) *optarg))
* parallel can over-run the kernel
* queues, and Linux will happily discard
* packets. So even if the server responds,
- * the client may not see the response.
+ * the client may not see the reply.
*/
case 'p':
parallel = atoi(optarg);
#endif
case 'q':
- do_output = 0;
+ do_output = false;
fr_log_fp = NULL; /* no output from you, either! */
break;
case 'r':
if ((retries == 0) || (retries > 1000)) usage();
break;
case 's':
- do_summary = 1;
+ do_summary = true;
break;
case 'S':
- fp = fopen(optarg, "r");
- if (!fp) {
- fprintf(stderr, "radclient: Error opening %s: %s\n",
- optarg, strerror(errno));
+ {
+ char *p;
+ fp = fopen(optarg, "r");
+ if (!fp) {
+ ERROR("Error opening %s: %s", optarg, fr_syserror(errno));
exit(1);
- }
- if (fgets(filesecret, sizeof(filesecret), fp) == NULL) {
- fprintf(stderr, "radclient: Error reading %s: %s\n",
- optarg, strerror(errno));
+ }
+ if (fgets(filesecret, sizeof(filesecret), fp) == NULL) {
+ ERROR("Error reading %s: %s", optarg, fr_syserror(errno));
exit(1);
- }
- fclose(fp);
+ }
+ fclose(fp);
- /* truncate newline */
- p = filesecret + strlen(filesecret) - 1;
- while ((p >= filesecret) &&
+ /* truncate newline */
+ p = filesecret + strlen(filesecret) - 1;
+ while ((p >= filesecret) &&
(*p < ' ')) {
*p = '\0';
--p;
- }
+ }
- if (strlen(filesecret) < 2) {
- fprintf(stderr, "radclient: Secret in %s is too short\n", optarg);
+ if (strlen(filesecret) < 2) {
+ ERROR("Secret in %s is too short", optarg);
exit(1);
- }
- secret = filesecret;
+ }
+ secret = filesecret;
+ }
break;
case 't':
if (!isdigit((int) *optarg))
timeout = atof(optarg);
break;
case 'v':
- printf("%s\n", radclient_version);
+ DEBUG("%s", radclient_version);
exit(0);
break;
case 'x':
fr_debug_flag++;
- fr_log_fp = stdout;
break;
case 'h':
default:
argc -= (optind - 1);
argv += (optind - 1);
- if ((argc < 3) ||
- ((secret == NULL) && (argc < 4))) {
+ if ((argc < 3) || ((secret == NULL) && (argc < 4))) {
+ ERROR("Insufficient arguments");
usage();
}
+ /*
+ * Mismatch between the binary and the libraries it depends on
+ */
+ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
+ fr_perror("radclient");
+ return 1;
+ }
+
+ if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) {
+ fr_perror("radclient");
+ return 1;
+ }
- if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) {
+ if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) {
fr_perror("radclient");
return 1;
}
+ fr_strerror(); /* Clear the error buffer */
+
+
+ /*
+ * Get the request type
+ */
+ if (!isdigit((int) argv[2][0])) {
+ packet_code = fr_str2int(request_types, argv[2], -2);
+ if (packet_code == -2) {
+ ERROR("Unrecognised request type \"%s\"", argv[2]);
+ usage();
+ }
+ } else {
+ packet_code = atoi(argv[2]);
+ }
/*
* Resolve hostname.
if (force_af == AF_UNSPEC) force_af = AF_INET;
server_ipaddr.af = force_af;
if (strcmp(argv[1], "-") != 0) {
+ char *p;
char const *hostname = argv[1];
char const *portname = argv[1];
char buffer[256];
portname = NULL;
}
- if (ip_hton(hostname, force_af, &server_ipaddr) < 0) {
- fprintf(stderr, "radclient: Failed to find IP address for host %s: %s\n", hostname, strerror(errno));
+ if (ip_hton(&server_ipaddr, force_af, hostname, false) < 0) {
+ ERROR("Failed to find IP address for host %s: %s", hostname, strerror(errno));
exit(1);
}
if (portname) server_port = atoi(portname);
}
- /*
- * See what kind of request we want to send.
- */
- if (strcmp(argv[2], "auth") == 0) {
- if (server_port == 0) server_port = getport("radius");
- if (server_port == 0) server_port = PW_AUTH_UDP_PORT;
- packet_code = PW_AUTHENTICATION_REQUEST;
-
- } else if (strcmp(argv[2], "challenge") == 0) {
- if (server_port == 0) server_port = getport("radius");
- if (server_port == 0) server_port = PW_AUTH_UDP_PORT;
- packet_code = PW_ACCESS_CHALLENGE;
-
- } else if (strcmp(argv[2], "acct") == 0) {
- if (server_port == 0) server_port = getport("radacct");
- if (server_port == 0) server_port = PW_ACCT_UDP_PORT;
- packet_code = PW_ACCOUNTING_REQUEST;
- do_summary = 0;
-
- } else if (strcmp(argv[2], "status") == 0) {
- if (server_port == 0) server_port = getport("radius");
- if (server_port == 0) server_port = PW_AUTH_UDP_PORT;
- packet_code = PW_STATUS_SERVER;
-
- } else if (strcmp(argv[2], "disconnect") == 0) {
- if (server_port == 0) server_port = PW_COA_UDP_PORT;
- packet_code = PW_DISCONNECT_REQUEST;
-
- } else if (strcmp(argv[2], "coa") == 0) {
- if (server_port == 0) server_port = PW_COA_UDP_PORT;
- packet_code = PW_COA_REQUEST;
-
- } else if (strcmp(argv[2], "auto") == 0) {
- packet_code = -1;
-
- } else if (isdigit((int) argv[2][0])) {
- if (server_port == 0) server_port = getport("radius");
- if (server_port == 0) server_port = PW_AUTH_UDP_PORT;
- packet_code = atoi(argv[2]);
- } else {
- usage();
- }
+ radclient_get_port(packet_code, &server_port);
/*
* Add the secret.
* If no '-f' is specified, we're reading from stdin.
*/
if (rbtree_num_elements(filename_tree) == 0) {
- if (!radclient_init("-")) exit(1);
+ rc_file_pair_t *files;
+
+ files = talloc_zero(talloc_autofree_context(), rc_file_pair_t);
+ files->packets = "-";
+ if (!radclient_init(files, files)) {
+ exit(1);
+ }
}
/*
* Walk over the list of filenames, creating the requests.
*/
- if (rbtree_walk(filename_tree, InOrder, filename_walk, NULL) != 0) {
- fprintf(stderr, "Failed walking over filenames\n");
+ if (rbtree_walk(filename_tree, RBTREE_IN_ORDER, filename_walk, NULL) != 0) {
+ ERROR("Failed parsing input files");
exit(1);
}
/*
* No packets read. Die.
*/
- if (!radclient_head) {
- fprintf(stderr, "radclient: Nothing to send.\n");
+ if (!request_head) {
+ ERROR("Nothing to send");
exit(1);
}
* Bind to the first specified IP address and port.
* This means we ignore later ones.
*/
- if (radclient_head->request->src_ipaddr.af == AF_UNSPEC) {
+ if (request_head->packet->src_ipaddr.af == AF_UNSPEC) {
memset(&client_ipaddr, 0, sizeof(client_ipaddr));
client_ipaddr.af = server_ipaddr.af;
client_port = 0;
} else {
- client_ipaddr = radclient_head->request->src_ipaddr;
- client_port = radclient_head->request->src_port;
+ client_ipaddr = request_head->packet->src_ipaddr;
+ client_port = request_head->packet->src_port;
}
#ifdef WITH_TCP
if (proto) {
#endif
sockfd = fr_socket(&client_ipaddr, client_port);
if (sockfd < 0) {
- fprintf(stderr, "radclient: socket: %s\n", fr_strerror());
+ ERROR("Error opening socket");
exit(1);
}
pl = fr_packet_list_create(1);
if (!pl) {
- fprintf(stderr, "radclient: Out of memory\n");
+ ERROR("Out of memory");
exit(1);
}
if (!fr_packet_list_socket_add(pl, sockfd, ipproto, &server_ipaddr,
server_port, NULL)) {
- fprintf(stderr, "radclient: Out of memory\n");
+ ERROR("Out of memory");
exit(1);
}
* Walk over the list of packets, sanity checking
* everything.
*/
- for (this = radclient_head; this != NULL; this = this->next) {
- this->request->src_ipaddr = client_ipaddr;
- this->request->src_port = client_port;
+ for (this = request_head; this != NULL; this = this->next) {
+ this->packet->src_ipaddr = client_ipaddr;
+ this->packet->src_port = client_port;
if (radclient_sane(this) != 0) {
exit(1);
}
*/
do {
int n = parallel;
- radclient_t *next;
+ rc_request_t *next;
char const *filename = NULL;
- done = 1;
+ done = true;
sleep_time = -1;
/*
* Walk over the packets, sending them.
*/
- for (this = radclient_head; this != NULL; this = next) {
+ for (this = request_head; this != NULL; this = next) {
next = this->next;
/*
* This packet is done. Delete it.
*/
if (this->done) {
- radclient_free(this);
+ talloc_free(this);
continue;
}
* which case N packets from each file
* are sent in parallel.
*/
- if (this->filename != filename) {
- filename = this->filename;
+ if (this->files->packets != filename) {
+ filename = this->files->packets;
n = parallel;
}
* and we shouldn't sleep.
*/
if (this->resend < resend_count) {
- done = 0;
+ done = false;
sleep_time = 0;
}
} else { /* haven't sent this packet, we're not done */
- assert(this->done == 0);
+ assert(this->done == false);
assert(this->reply == NULL);
- done = 0;
+ done = false;
}
}
* Still have outstanding requests.
*/
if (fr_packet_list_num_elements(pl) > 0) {
- done = 0;
+ done = false;
} else {
sleep_time = 0;
}
rbtree_free(filename_tree);
fr_packet_list_free(pl);
- while (radclient_head) radclient_free(radclient_head);
+ while (request_head) TALLOC_FREE(request_head);
dict_free();
if (do_summary) {
- printf("\n\t Total approved auths: %d\n", totalapp);
- printf("\t Total denied auths: %d\n", totaldeny);
- printf("\t Total lost auths: %d\n", totallost);
+ DEBUG("Packet summary:\n"
+ "\tAccess-Accepts : %" PRIu64 "\n"
+ "\tAccess-Rejects : %" PRIu64 "\n"
+ "\tLost : %" PRIu64 "\n"
+ "\tPassed filter : %" PRIu64 "\n"
+ "\tFailed filter : %" PRIu64,
+ stats.accepted,
+ stats.rejected,
+ stats.lost,
+ stats.passed,
+ stats.failed
+ );
}
- if (success) return 0;
-
- return 1;
+ if ((stats.lost > 0) || (stats.failed > 0)) {
+ exit(1);
+ }
+ exit(0);
}
+++ /dev/null
-/*
- * radconf2xml.c Converts radiusd.conf to XML.
- *
- * Version: $Id$
- *
- * 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
- *
- * Copyright 2008 The FreeRADIUS server project
- * Copyright 2008 Alan DeKok <aland@deployingradius.com>
- */
-
-RCSID("$Id$")
-
-#include <freeradius-devel/radiusd.h>
-
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#endif
-
-/*
- * For configuration file stuff.
- */
-char const *raddb_dir = RADDBDIR;
-char const *progname = "radconf2xml";
-
-/*
- * The rest of this is because the conffile.c, etc. assume
- * they're running inside of the server. And we don't (yet)
- * have a "libfreeradius-server", or "libfreeradius-util".
- */
-log_debug_t debug_flag = 0;
-struct main_config_t mainconfig;
-char *request_log_file = NULL;
-char *debug_log_file = NULL;
-
-#include <sys/wait.h>
-pid_t rad_fork(void)
-{
- return fork();
-}
-
-#ifdef HAVE_PTHREAD_H
-pid_t rad_waitpid(pid_t pid, int *status)
-{
- return waitpid(pid, status, 0);
-}
-#endif
-
-bool check_config = false;
-
-static int usage(void)
-{
- printf("Usage: %s [ -d raddb_dir ] [ -o output_file ] [ -n name ]\n", progname);
- printf(" -d raddb_dir Configuration files are in \"raddbdir/*\".\n");
- printf(" -n name Read raddb/name.conf instead of raddb/radiusd.conf\n");
- printf(" -o output_file File where XML output will be written.\n");
-
- exit(1);
-}
-
-int main(int argc, char **argv)
-{
- int argval;
- CONF_SECTION *cs;
- char const *file = NULL;
- char const *name = "radiusd";
- FILE *fp;
- char buffer[2048];
-
- if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL)
- progname = argv[0];
- else
- progname++;
-
- while ((argval = getopt(argc, argv, "d:ho:n:")) != EOF) {
- switch(argval) {
- case 'd':
- if (file) {
- fprintf(stderr, "%s: -d and -f cannot be used together.\n", progname);
- exit(1);
- }
- raddb_dir = optarg;
- break;
-
- default:
- case 'h':
- usage();
- break;
-
- case 'n':
- name = optarg;
- break;
-
- case 'o':
- file = optarg;
- break;
- }
- }
-
- snprintf(buffer, sizeof(buffer), "%s/%s.conf", raddb_dir, name);
- cs = cf_file_read(buffer);
- if (!cs) {
- fprintf(stderr, "%s: Errors reading or parsing %s\n",
- progname, buffer);
- exit(1);
- }
-
- if (!file || (strcmp(file, "-") == 0)) {
- fp = stdout;
- file = NULL;
- } else {
- fp = fopen(file, "w");
- if (!fp) {
- fprintf(stderr, "%s: Failed openng %s: %s\n",
- progname, file, strerror(errno));
- exit(1);
- }
- }
-
- if (!cf_section2xml(fp, cs)) {
- if (file) unlink(file);
- return 1;
- }
-
- return 0;
-}
+++ /dev/null
-TARGET := radconf2xml
-SOURCES := radconf2xml.c
-
-TGT_PREREQS := libfreeradius-server.a libfreeradius-radius.a
-TGT_LDLIBS := $(LIBS)
#include <fcntl.h>
#include <ctype.h>
-#include <signal.h>
-
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#endif
bool log_stripped_names;
log_debug_t debug_flag = 0;
bool check_config = false;
-bool memory_report = false;
char const *radiusd_version = "FreeRADIUS Version " RADIUSD_VERSION_STRING
#ifdef RADIUSD_VERSION_COMMIT
-" (git #" RADIUSD_VERSION_COMMIT ")"
+" (git #" STRINGIFY(RADIUSD_VERSION_COMMIT) ")"
#endif
", for host " HOSTINFO ", built on " __DATE__ " at " __TIME__;
static void sig_hup (int);
#endif
-#ifdef WITH_VERIFY_PTR
-static void die_horribly(char const *reason)
-{
- ERROR("talloc abort: %s\n", reason);
- abort();
-}
-#endif
-
/*
* The main guy.
*/
int rcode = EXIT_SUCCESS;
int status;
int argval;
- int spawn_flag = true;
- int dont_fork = false;
- int write_pid = false;
+ bool spawn_flag = true;
+ bool write_pid = false;
+ bool display_version = false;
int flag = 0;
int from_child[2] = {-1, -1};
-#ifdef HAVE_SIGACTION
- struct sigaction act;
+ /*
+ * We probably don't want to free the talloc autofree context
+ * directly, so we'll allocate a new context beneath it, and
+ * free that before any leak reports.
+ */
+ 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
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
- fprintf(stderr, "%s: Unable to initialize socket library.\n", progname);
- return 1;
+ fprintf(stderr, "%s: Unable to initialize socket library.\n", progname);
+ exit(EXIT_FAILURE);
}
}
#endif
debug_flag = 0;
- spawn_flag = true;
- radius_dir = talloc_strdup(NULL, RADIUS_DIR);
+ set_radius_dir(autofree, RADIUS_DIR);
/*
* Ensure that the configuration is initialized.
*/
- memset(&mainconfig, 0, sizeof(mainconfig));
- mainconfig.myip.af = AF_UNSPEC;
- mainconfig.port = -1;
- mainconfig.name = "radiusd";
-
-#ifdef HAVE_SIGACTION
- memset(&act, 0, sizeof(act));
- act.sa_flags = 0 ;
- sigemptyset( &act.sa_mask ) ;
-#endif
+ memset(&main_config, 0, sizeof(main_config));
+ main_config.myip.af = AF_UNSPEC;
+ main_config.port = 0;
+ main_config.name = "radiusd";
+ main_config.daemonize = true;
/*
* Don't put output anywhere until we get told a little
* more.
*/
- default_log.dest = L_DST_NULL;
+ default_log.dst = L_DST_NULL;
default_log.fd = -1;
- mainconfig.log_file = NULL;
+ main_config.log_file = NULL;
/* Process the options. */
while ((argval = getopt(argc, argv, "Cd:D:fhi:l:mMn:p:PstvxX")) != EOF) {
case 'C':
check_config = true;
spawn_flag = false;
- dont_fork = true;
+ main_config.daemonize = false;
break;
case 'd':
- if (radius_dir) {
- rad_const_free(radius_dir);
- }
- radius_dir = talloc_strdup(NULL, optarg);
+ set_radius_dir(autofree, optarg);
break;
case 'D':
- mainconfig.dictionary_dir = talloc_strdup(NULL, optarg);
+ main_config.dictionary_dir = talloc_typed_strdup(NULL, optarg);
break;
case 'f':
- dont_fork = true;
+ main_config.daemonize = false;
break;
case 'h':
if (strcmp(optarg, "stdout") == 0) {
goto do_stdout;
}
- mainconfig.log_file = strdup(optarg);
- default_log.dest = L_DST_FILES;
- default_log.fd = open(mainconfig.log_file,
+ main_config.log_file = strdup(optarg);
+ default_log.dst = L_DST_FILES;
+ default_log.fd = open(main_config.log_file,
O_WRONLY | O_APPEND | O_CREAT, 0640);
if (default_log.fd < 0) {
- fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", mainconfig.log_file, strerror(errno));
+ fprintf(stderr, "radiusd: Failed to open log file %s: %s\n", main_config.log_file, fr_syserror(errno));
exit(EXIT_FAILURE);
}
fr_log_fp = fdopen(default_log.fd, "a");
break;
case 'i':
- if (ip_hton(optarg, AF_UNSPEC, &mainconfig.myip) < 0) {
+ if (ip_hton(&main_config.myip, AF_UNSPEC, optarg, false) < 0) {
fprintf(stderr, "radiusd: Invalid IP Address or hostname \"%s\"\n", optarg);
exit(EXIT_FAILURE);
}
break;
case 'n':
- mainconfig.name = optarg;
+ main_config.name = optarg;
break;
case 'm':
- mainconfig.debug_memory = 1;
+ main_config.debug_memory = true;
break;
case 'M':
- memory_report = 1;
- mainconfig.debug_memory = 1;
+ main_config.memory_report = true;
+ main_config.debug_memory = true;
break;
case 'p':
- mainconfig.port = atoi(optarg);
- if ((mainconfig.port <= 0) ||
- (mainconfig.port >= 65536)) {
- fprintf(stderr, "radiusd: Invalid port number %s\n", optarg);
+ {
+ unsigned long port;
+
+ port = strtoul(optarg, 0, 10);
+ if ((port == 0) || (port > UINT16_MAX)) {
+ fprintf(stderr, "radiusd: Invalid port number \"%s\"\n", optarg);
exit(EXIT_FAILURE);
}
+
+ main_config.port = (uint16_t) port;
flag |= 2;
+ }
break;
case 'P':
case 's': /* Single process mode */
spawn_flag = false;
- dont_fork = true;
+ main_config.daemonize = false;
break;
case 't': /* no child threads */
break;
case 'v':
- /* Don't print timestamps */
- debug_flag += 2;
- fr_log_fp = stdout;
- default_log.dest = L_DST_STDOUT;
- default_log.fd = STDOUT_FILENO;
+ display_version = true;
+ break;
- version();
- exit(EXIT_SUCCESS);
case 'X':
spawn_flag = false;
- dont_fork = true;
+ main_config.daemonize = false;
debug_flag += 2;
- mainconfig.log_auth = true;
- mainconfig.log_auth_badpass = true;
- mainconfig.log_auth_goodpass = true;
+ main_config.log_auth = true;
+ main_config.log_auth_badpass = true;
+ main_config.log_auth_goodpass = true;
do_stdout:
fr_log_fp = stdout;
- default_log.dest = L_DST_STDOUT;
+ default_log.dst = L_DST_STDOUT;
default_log.fd = STDOUT_FILENO;
break;
}
}
- if (memory_report) {
- talloc_enable_null_tracking();
-#ifdef WITH_VERIFY_PTR
- talloc_set_abort_fn(die_horribly);
-#endif
+ /*
+ * Mismatch between the binary and the libraries it depends on
+ */
+ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
+ fr_perror("radiusd");
+ exit(EXIT_FAILURE);
+ }
+
+ if (rad_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
+ exit(EXIT_FAILURE);
}
- talloc_set_log_fn(log_talloc);
/*
* Mismatch between build time OpenSSL and linked SSL,
* better to die here than segfault later.
*/
#ifdef HAVE_OPENSSL_CRYPTO_H
- if (ssl_check_version() < 0) {
+ if (ssl_check_consistency() < 0) {
exit(EXIT_FAILURE);
}
-
- /*
- * Initialising OpenSSL once, here, is safer than having individual
- * modules do it.
- */
- tls_global_init();
#endif
if (flag && (flag != 0x03)) {
exit(EXIT_FAILURE);
}
+ /*
+ * Better here, so it doesn't matter whether we get passed
+ * -xv or -vx.
+ */
+ if (display_version) {
+ /* Don't print timestamps */
+ debug_flag += 2;
+ fr_log_fp = stdout;
+ default_log.dst = L_DST_STDOUT;
+ default_log.fd = STDOUT_FILENO;
+
+ version();
+ exit(EXIT_SUCCESS);
+ }
+
if (debug_flag) {
version();
}
+ /*
+ * Initialising OpenSSL once, here, is safer than having individual
+ * modules do it.
+ */
+#ifdef HAVE_OPENSSL_CRYPTO_H
+ tls_global_init();
+#endif
+
+ /*
+ * Initialize any event loops just enough so module instantiations
+ * can add fd/event to them, but do not start them yet.
+ */
+ if (!radius_event_init(autofree)) {
+ exit(EXIT_FAILURE);
+ }
+
/* Read the configuration files, BEFORE doing anything else. */
- if (read_mainconfig(0) < 0) {
+ if (main_config_init() < 0) {
+ exit(EXIT_FAILURE);
+ }
+
+ /* Check for vulnerabilities in the version of libssl were linked against */
+#ifdef HAVE_OPENSSL_CRYPTO_H
+ if (tls_global_version_check(main_config.allow_vulnerable_openssl) < 0) {
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+ /*
+ * Load the modules
+ */
+ if (modules_init(main_config.config) < 0) {
+ exit(EXIT_FAILURE);
+ }
+
+ /* Set the panic action (if required) */
+ if (main_config.panic_action &&
+#ifndef NDEBUG
+ !getenv("PANIC_ACTION") &&
+#endif
+ (fr_fault_setup(main_config.panic_action, argv[0]) < 0)) {
+ fr_perror("radiusd");
exit(EXIT_FAILURE);
}
#ifndef __MINGW32__
+
+
/*
* Disconnect from session
*/
- if (dont_fork == false) {
+ if (main_config.daemonize) {
pid_t pid;
+ int devnull;
+
+ /*
+ * Really weird things happen if we leave stdin open and call things like
+ * system() later.
+ */
+ devnull = open("/dev/null", O_RDWR);
+ if (devnull < 0) {
+ ERROR("Failed opening /dev/null: %s", fr_syserror(errno));
+ exit(EXIT_FAILURE);
+ }
+ dup2(devnull, STDIN_FILENO);
+
+ close(devnull);
if (pipe(from_child) != 0) {
- ERROR("Couldn't open pipe for child status: %s", strerror(errno));
+ ERROR("Couldn't open pipe for child status: %s", fr_syserror(errno));
exit(EXIT_FAILURE);
}
pid = fork();
if (pid < 0) {
- ERROR("Couldn't fork: %s", strerror(errno));
+ ERROR("Couldn't fork: %s", fr_syserror(errno));
exit(EXIT_FAILURE);
}
/* so the pipe is correctly widowed if the parent exits?! */
close(from_child[0]);
-#ifdef HAVE_SETSID
+# ifdef HAVE_SETSID
setsid();
-#endif
+# endif
}
#endif
/*
- * Ensure that we're using the CORRECT pid after forking,
- * NOT the one we started with.
+ * Ensure that we're using the CORRECT pid after forking,
+ * NOT the one we started with.
*/
radius_pid = getpid();
/*
- * If we're running as a daemon, close the default file
- * descriptors, AFTER forking.
+ * Redirect stderr/stdout as appropriate.
*/
- if (!debug_flag) {
- int devnull;
-
- devnull = open("/dev/null", O_RDWR);
- if (devnull < 0) {
- ERROR("Failed opening /dev/null: %s\n",
- strerror(errno));
- exit(EXIT_FAILURE);
- }
- dup2(devnull, STDIN_FILENO);
- if (default_log.dest == L_DST_STDOUT) {
- setlinebuf(stdout);
- default_log.fd = STDOUT_FILENO;
- } else {
- dup2(devnull, STDOUT_FILENO);
- }
- if (default_log.dest == L_DST_STDERR) {
- setlinebuf(stderr);
- default_log.fd = STDERR_FILENO;
- } else {
- dup2(devnull, STDERR_FILENO);
- }
- close(devnull);
-
- } else {
- setlinebuf(stdout); /* unbuffered output */
+ if (radlog_init(&default_log, main_config.daemonize) < 0) {
+ ERROR("%s", fr_strerror());
+ exit(EXIT_FAILURE);
}
/*
- * Now we have logging check that the OpenSSL
- */
-
- /*
- * Initialize the event pool, including threads.
+ * Start the event loop(s) and threads.
*/
- radius_event_init(mainconfig.config, spawn_flag);
+ radius_event_start(main_config.config, spawn_flag);
/*
* Now that we've set everything up, we can install the signal
#ifdef SIGPIPE
signal(SIGPIPE, SIG_IGN);
#endif
-#ifdef HAVE_SIGACTION
- act.sa_handler = sig_hup;
- sigaction(SIGHUP, &act, NULL);
- act.sa_handler = sig_fatal;
- sigaction(SIGTERM, &act, NULL);
-#else
-#ifdef SIGHUP
- signal(SIGHUP, sig_hup);
-#endif
- signal(SIGTERM, sig_fatal);
-#endif
+
+ if ((fr_set_signal(SIGHUP, sig_hup) < 0) ||
+ (fr_set_signal(SIGTERM, sig_fatal) < 0)) {
+ ERROR("%s", fr_strerror());
+ exit(EXIT_FAILURE);
+ }
+
/*
* If we're debugging, then a CTRL-C will cause the
* server to die immediately. Use SIGTERM to shut down
* the server cleanly in that case.
*/
- if ((mainconfig.debug_memory == 1) || (debug_flag == 0)) {
-#ifdef HAVE_SIGACTION
- act.sa_handler = sig_fatal;
- sigaction(SIGINT, &act, NULL);
- sigaction(SIGQUIT, &act, NULL);
-#else
- signal(SIGINT, sig_fatal);
+ if (main_config.debug_memory || (debug_flag == 0)) {
+ if ((fr_set_signal(SIGINT, sig_fatal) < 0)
#ifdef SIGQUIT
- signal(SIGQUIT, sig_fatal);
-#endif
+ || (fr_set_signal(SIGQUIT, sig_fatal) < 0)
#endif
+ ) {
+ ERROR("%s", fr_strerror());
+ exit(EXIT_FAILURE);
+ }
}
/*
* Everything seems to have loaded OK, exit gracefully.
*/
if (check_config) {
- DEBUG("Configuration appears to be OK.");
+ DEBUG("Configuration appears to be OK");
/* for -C -m|-M */
- if (mainconfig.debug_memory) {
+ if (main_config.debug_memory) {
goto cleanup;
}
#endif
/*
- * Write out the PID anyway if were in foreground mode.
+ * Write the PID always if we're running as a daemon.
*/
- if (!dont_fork) write_pid = true;
+ if (main_config.daemonize) write_pid = true;
/*
- * Only write the PID file if we're running as a daemon.
- *
- * And write it AFTER we've forked, so that we write the
- * correct PID.
+ * Write the PID after we've forked, so that we write the
+ * correct one.
*/
if (write_pid) {
FILE *fp;
- fp = fopen(mainconfig.pid_file, "w");
+ fp = fopen(main_config.pid_file, "w");
if (fp != NULL) {
/*
* FIXME: What about following symlinks,
fclose(fp);
} else {
ERROR("Failed creating PID file %s: %s\n",
- mainconfig.pid_file, strerror(errno));
+ main_config.pid_file, fr_syserror(errno));
exit(EXIT_FAILURE);
}
}
* we just close the pipe on exit, and the parent gets a
* read failure.
*/
- if (!dont_fork) {
+ if (main_config.daemonize) {
if (write(from_child[1], "\001", 1) < 0) {
WARN("Failed informing parent of successful start: %s",
- strerror(errno));
+ fr_syserror(errno));
}
close(from_child[1]);
}
/*
+ * Clear the libfreeradius error buffer
+ */
+ fr_strerror();
+
+ /*
* Process requests until HUP or exit.
*/
while ((status = radius_event_process()) == 0x80) {
#ifdef WITH_STATS
radius_stats_init(1);
#endif
- hup_mainconfig();
+ main_config_hup();
}
if (status < 0) {
ERROR("Exiting due to internal error: %s", fr_strerror());
rcode = EXIT_FAILURE;
} else {
- INFO("Exiting normally.");
+ INFO("Exiting normally");
}
exec_trigger(NULL, NULL, "server.stop", false);
* file. (If it doesn't exist, we can ignore
* the error returned by unlink)
*/
- if (dont_fork == false) {
- unlink(mainconfig.pid_file);
+ if (main_config.daemonize) {
+ unlink(main_config.pid_file);
}
radius_event_free();
/*
* Detach any modules.
*/
- detach_modules();
+ modules_free();
xlat_free(); /* modules may have xlat's */
/*
* Free the configuration items.
*/
- free_mainconfig();
-
- rad_const_free(radius_dir);
+ main_config_free();
#ifdef WIN32
WSACleanup();
#endif
- if (memory_report) {
+#ifdef HAVE_OPENSSL_CRYPTO_H
+ tls_global_cleanup();
+#endif
+
+ /*
+ * So we don't see autofreed memory in the talloc report
+ */
+ talloc_free(autofree);
+
+ if (main_config.memory_report) {
INFO("Allocated memory at time of report:");
- log_talloc_report(NULL);
+ fr_log_talloc_report(NULL);
}
return rcode;
{
FILE *output = status?stderr:stdout;
- fprintf(output, "Usage: %s [-d db_dir] [-l log_dir] [-i address] [-n name] [-fsvXx]\n", progname);
+ fprintf(output, "Usage: %s [options]\n", progname);
fprintf(output, "Options:\n");
fprintf(output, " -C Check configuration and exit.\n");
- fprintf(output, " -d raddb_dir Configuration files are in \"raddbdir/*\".\n");
+ fprintf(stderr, " -d <raddb> Set configuration directory (defaults to " RADDBDIR ").\n");
+ fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
fprintf(output, " -f Run as a foreground process, not a daemon.\n");
fprintf(output, " -h Print this help message.\n");
- fprintf(output, " -i ipaddr Listen on ipaddr ONLY.\n");
- fprintf(output, " -l log_file Logging output will be written to this file.\n");
+ fprintf(output, " -i <ipaddr> Listen on ipaddr ONLY.\n");
+ fprintf(output, " -l <log_file> Logging output will be written to this file.\n");
fprintf(output, " -m On SIGINT or SIGQUIT exit cleanly instead of immediately.\n");
- fprintf(output, " -n name Read raddb/name.conf instead of raddb/radiusd.conf.\n");
- fprintf(output, " -p port Listen on port ONLY.\n");
+ fprintf(output, " -n <name> Read raddb/name.conf instead of raddb/radiusd.conf.\n");
+ fprintf(output, " -p <port> Listen on port ONLY.\n");
fprintf(output, " -P Always write out PID, even with -f.\n");
fprintf(output, " -s Do not spawn child processes to handle requests.\n");
fprintf(output, " -t Disable threads.\n");
if (getpid() != radius_pid) _exit(sig);
switch(sig) {
- case SIGTERM:
- radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
- break;
+ case SIGTERM:
+ radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
+ break;
- case SIGINT:
+ case SIGINT:
#ifdef SIGQUIT
- case SIGQUIT:
+ case SIGQUIT:
#endif
- if (mainconfig.debug_memory || memory_report) {
- radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
- break;
- }
- /* FALL-THROUGH */
+ if (main_config.debug_memory || main_config.memory_report) {
+ radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
+ break;
+ }
+ /* FALL-THROUGH */
- default:
- _exit(sig);
+ default:
+ _exit(sig);
}
}
/*
* For configuration file stuff.
*/
-char const *radius_dir = RADDBDIR;
char const *progname = "radmin";
char const *radmin_version = "radmin version " RADIUSD_VERSION_STRING
#ifdef RADIUSD_VERSION_COMMIT
-" (git #" RADIUSD_VERSION_COMMIT ")"
+" (git #" STRINGIFY(RADIUSD_VERSION_COMMIT) ")"
#endif
", built on " __DATE__ " at " __TIME__;
* have a "libfreeradius-server", or "libfreeradius-util".
*/
log_debug_t debug_flag = 0;
-struct main_config_t mainconfig;
+struct main_config_t main_config;
bool check_config = false;
static FILE *outputfp = NULL;
-static int echo = false;
+static bool echo = false;
static char const *secret = "testing123";
#include <sys/wait.h>
FILE *output = status ? stderr : stdout;
fprintf(output, "Usage: %s [ args ]\n", progname);
fprintf(output, " -d raddb_dir Configuration files are in \"raddbdir/*\".\n");
+ fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
fprintf(output, " -e command Execute 'command' and then exit.\n");
fprintf(output, " -E Echo commands as they are being executed.\n");
fprintf(output, " -f socket_file Open socket_file directly, without reading radius.conf\n");
if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "%s: Failed creating socket: %s\n",
- progname, strerror(errno));
+ progname, fr_syserror(errno));
return -1;
}
close(sockfd);
fprintf(stderr, "%s: Failed connecting to %s: %s\n",
- progname, path, strerror(errno));
+ progname, path, fr_syserror(errno));
/*
* The file doesn't exist. Tell the user how to
if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0) {
fprintf(stderr, "%s: Failure getting socket flags: %s",
- progname, strerror(errno));
+ progname, fr_syserror(errno));
close(sockfd);
return -1;
}
flags |= O_NONBLOCK;
if( fcntl(sockfd, F_SETFL, flags) < 0) {
fprintf(stderr, "%s: Failure setting socket flags: %s",
- progname, strerror(errno));
+ progname, fr_syserror(errno));
close(sockfd);
return -1;
}
static int client_socket(char const *server)
{
- int sockfd, port;
+ int sockfd;
+ uint16_t port;
fr_ipaddr_t ipaddr;
char *p, buffer[1024];
*p = '\0';
}
- if (ip_hton(buffer, AF_INET, &ipaddr) < 0) {
+ if (ip_hton(&ipaddr, AF_INET, buffer, false) < 0) {
fprintf(stderr, "%s: Failed looking up host %s: %s\n",
- progname, buffer, strerror(errno));
+ progname, buffer, fr_syserror(errno));
exit(1);
}
sockfd = fr_tcp_client_socket(NULL, &ipaddr, port);
if (sockfd < 0) {
fprintf(stderr, "%s: Failed opening socket %s: %s\n",
- progname, server, strerror(errno));
+ progname, server, fr_syserror(errno));
exit(1);
}
if (errno == EINTR) continue;
fprintf(stderr, "%s: Failed reading data: %s\n",
- progname, strerror(errno));
+ progname, fr_syserror(errno));
exit(1);
}
total += r;
if (write(sockfd, challenge, sizeof(challenge)) < 0) {
fprintf(stderr, "%s: Failed writing challenge data: %s\n",
- progname, strerror(errno));
+ progname, fr_syserror(errno));
}
}
if (errno == EINTR) continue;
fprintf(stderr, "%s: Failed selecting: %s\n",
- progname, strerror(errno));
+ progname, fr_syserror(errno));
exit(1);
}
}
fprintf(stderr, "%s: Error reading socket: %s\n",
- progname, strerror(errno));
+ progname, fr_syserror(errno));
exit(1);
}
if (len == 0) return 0; /* clean exit */
int main(int argc, char **argv)
{
- int argval, quiet = 0;
- int done_license = 0;
- int sockfd;
- uint32_t magic, needed;
- char *line = NULL;
- ssize_t len, size;
- char const *file = NULL;
- char const *name = "radiusd";
- char *p, buffer[65536];
- char const *input_file = NULL;
- FILE *inputfp = stdin;
- char const *output_file = NULL;
- char const *server = NULL;
+ int argval;
+ bool quiet = false;
+ bool done_license = false;
+ int sockfd;
+ uint32_t magic, needed;
+ char *line = NULL;
+ ssize_t len, size;
+ char const *file = NULL;
+ char const *name = "radiusd";
+ char *p, buffer[65536];
+ char const *input_file = NULL;
+ FILE *inputfp = stdin;
+ char const *output_file = NULL;
+ char const *server = NULL;
+
+ char const *radius_dir = RADIUS_DIR;
+ char const *dict_dir = DICTDIR;
char *commands[MAX_COMMANDS];
int num_commands = -1;
+#ifndef NDEBUG
+ if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
+ fr_perror("radmin");
+ exit(EXIT_FAILURE);
+ }
+#endif
+
talloc_set_log_stderr();
outputfp = stdout; /* stdout is not a constant value... */
- if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL)
+ if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL) {
progname = argv[0];
- else
+ } else {
progname++;
+ }
- while ((argval = getopt(argc, argv, "d:hi:e:Ef:n:o:qs:S")) != EOF) {
+ while ((argval = getopt(argc, argv, "d:D:hi:e:Ef:n:o:qs:S")) != EOF) {
switch(argval) {
case 'd':
if (file) {
radius_dir = optarg;
break;
+ case 'D':
+ dict_dir = optarg;
+ break;
+
case 'e':
num_commands++; /* starts at -1 */
if (num_commands >= MAX_COMMANDS) {
if (strcmp(optarg, "-") != 0) {
input_file = optarg;
}
- quiet = 1;
+ quiet = true;
break;
case 'n':
if (strcmp(optarg, "-") != 0) {
output_file = optarg;
}
- quiet = 1;
+ quiet = true;
break;
case 'q':
- quiet = 1;
+ quiet = true;
break;
case 's':
}
}
+ /*
+ * Mismatch between the binary and the libraries it depends on
+ */
+ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
+ fr_perror("radmin");
+ exit(1);
+ }
+
if (radius_dir) {
int rcode;
CONF_SECTION *cs, *subcs;
file = NULL; /* MUST read it from the conffile now */
- snprintf(buffer, sizeof(buffer), "%s/%s.conf",
- radius_dir, name);
+ snprintf(buffer, sizeof(buffer), "%s/%s.conf", radius_dir, name);
+
+ /*
+ * Need to read in the dictionaries, else we may get
+ * validation errors when we try and parse the config.
+ */
+ if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) {
+ fr_perror("radmin");
+ exit(64);
+ }
+
+ if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) {
+ fr_perror("radmin");
+ exit(64);
+ }
cs = cf_file_read(buffer);
if (!cs) {
/*
* Now find the socket name (sigh)
*/
- rcode = cf_item_parse(subcs, "socket",
- PW_TYPE_STRING_PTR,
- &file, NULL);
+ rcode = cf_item_parse(subcs, "socket", FR_ITEM_POINTER(PW_TYPE_STRING, &file), NULL);
if (rcode < 0) {
fprintf(stderr, "%s: Failed parsing listen section\n", progname);
exit(1);
if (input_file) {
inputfp = fopen(input_file, "r");
if (!inputfp) {
- fprintf(stderr, "%s: Failed opening %s: %s\n", progname, input_file, strerror(errno));
+ fprintf(stderr, "%s: Failed opening %s: %s\n", progname, input_file, fr_syserror(errno));
exit(1);
}
}
if (output_file) {
outputfp = fopen(output_file, "w");
if (!outputfp) {
- fprintf(stderr, "%s: Failed creating %s: %s\n", progname, output_file, strerror(errno));
+ fprintf(stderr, "%s: Failed creating %s: %s\n", progname, output_file, fr_syserror(errno));
exit(1);
}
}
+ if (!file && !server) {
+ fprintf(stderr, "%s: Must use one of '-d' or '-f' or '-s'\n",
+ progname);
+ exit(1);
+ }
+
/*
* Check if stdin is a TTY only if input is from stdin
*/
- if (input_file && !quiet && !isatty(STDIN_FILENO)) quiet = 1;
+ if (input_file && !quiet && !isatty(STDIN_FILENO)) quiet = true;
#ifdef USE_READLINE
if (!quiet) {
len = read(sockfd, buffer + size, 8 - size);
if (len < 0) {
fprintf(stderr, "%s: Error reading initial data from socket: %s\n",
- progname, strerror(errno));
+ progname, fr_syserror(errno));
exit(1);
}
}
printf("You may redistribute copies of FreeRADIUS under the terms of the\n");
printf("GNU General Public License v2.\n");
- done_license = 1;
+ done_license = true;
}
/*
/*
- * radsniff.c Display the RADIUS traffic on the network.
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 if the
+ * License as published by the Free Software Foundation.
*
- * Version: $Id$
+ * 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.
*
- * 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
+ * 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
+ */
+
+/**
+ * $Id$
+ * @file radsniff.c
+ * @brief Capture, filter, and generate statistics for RADIUS traffic
*
- * Copyright 2006 The FreeRADIUS server project
- * Copyright 2006 Nicolas Baradakis <nicolas.baradakis@cegetel.net>
+ * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2006 The FreeRADIUS server project
+ * @copyright 2006 Nicolas Baradakis <nicolas.baradakis@cegetel.net>
*/
RCSID("$Id$")
#define _LIBRADIUS 1
+#include <assert.h>
+#include <time.h>
+#include <math.h>
#include <freeradius-devel/libradius.h>
-
-#include <pcap.h>
+#include <freeradius-devel/event.h>
#include <freeradius-devel/radpaths.h>
#include <freeradius-devel/conf.h>
+#include <freeradius-devel/pcap.h>
#include <freeradius-devel/radsniff.h>
-static char const *radius_secret = "testing123";
-static VALUE_PAIR *filter_vps = NULL;
-
-static int do_sort = 0;
-static int to_stdout = 0;
-static FILE *log_dst;
-
-#ifndef PCAP_NETMASK_UNKNOWN
-# define PCAP_NETMASK_UNKNOWN 0
+#ifdef HAVE_COLLECTDC_H
+# include <collectd/client.h>
#endif
-#undef DEBUG1
-#define DEBUG1 if (fr_debug_flag > 2) fprintf
-#undef DEBUG
-#define DEBUG if (fr_debug_flag > 1) fprintf
-#undef INFO
-#define INFO if (fr_debug_flag > 0) fprintf
-
+static rs_t *conf;
struct timeval start_pcap = {0, 0};
-static rbtree_t *filter_tree = NULL;
+static char timestr[50];
+
static rbtree_t *request_tree = NULL;
-static pcap_dumper_t *out = NULL;
-static RADIUS_PACKET *nullpacket = NULL;
+static rbtree_t *link_tree = NULL;
+static fr_event_list_t *events;
+static bool cleanup;
+
+static int self_pipe[2] = {-1, -1}; //!< Signals from sig handlers
typedef int (*rbcmp)(void const *, void const *);
static char const *radsniff_version = "radsniff version " RADIUSD_VERSION_STRING
#ifdef RADIUSD_VERSION_COMMIT
-" (git #" RADIUSD_VERSION_COMMIT ")"
+" (git #" STRINGIFY(RADIUSD_VERSION_COMMIT) ")"
#endif
", built on " __DATE__ " at " __TIME__;
-static int filter_packet(RADIUS_PACKET *packet)
+static int rs_useful_codes[] = {
+ PW_CODE_AUTHENTICATION_REQUEST, //!< RFC2865 - Authentication request
+ PW_CODE_AUTHENTICATION_ACK, //!< RFC2865 - Access-Accept
+ PW_CODE_AUTHENTICATION_REJECT, //!< RFC2865 - Access-Reject
+ PW_CODE_ACCOUNTING_REQUEST, //!< RFC2866 - Accounting-Request
+ PW_CODE_ACCOUNTING_RESPONSE, //!< RFC2866 - Accounting-Response
+ PW_CODE_ACCESS_CHALLENGE, //!< RFC2865 - Access-Challenge
+ PW_CODE_STATUS_SERVER, //!< RFC2865/RFC5997 - Status Server (request)
+ PW_CODE_STATUS_CLIENT, //!< RFC2865/RFC5997 - Status Server (response)
+ PW_CODE_DISCONNECT_REQUEST, //!< RFC3575/RFC5176 - Disconnect-Request
+ PW_CODE_DISCONNECT_ACK, //!< RFC3575/RFC5176 - Disconnect-Ack (positive)
+ PW_CODE_DISCONNECT_NAK, //!< RFC3575/RFC5176 - Disconnect-Nak (not willing to perform)
+ PW_CODE_COA_REQUEST, //!< RFC3575/RFC5176 - CoA-Request
+ PW_CODE_COA_ACK, //!< RFC3575/RFC5176 - CoA-Ack (positive)
+ PW_CODE_COA_NAK, //!< RFC3575/RFC5176 - CoA-Nak (not willing to perform)
+};
+
+const FR_NAME_NUMBER rs_events[] = {
+ { "received", RS_NORMAL },
+ { "norsp", RS_LOST },
+ { "rtx", RS_RTX },
+ { "noreq", RS_UNLINKED },
+ { "reused", RS_REUSED },
+ { "error", RS_ERROR },
+ { NULL , -1 }
+};
+
+static void NEVER_RETURNS usage(int status);
+
+/** Fork and kill the parent process, writing out our PID
+ *
+ * @param pidfile the PID file to write our PID to
+ */
+static void rs_daemonize(char const *pidfile)
{
- vp_cursor_t cursor, check_cursor;
- VALUE_PAIR *check_item;
- VALUE_PAIR *vp;
- unsigned int pass, fail;
- int compare;
+ FILE *fp;
+ pid_t pid, sid;
- pass = fail = 0;
- for (vp = paircursor(&cursor, &packet->vps);
- vp;
- vp = pairnext(&cursor)) {
- for (check_item = paircursor(&check_cursor, &filter_vps);
- check_item;
- check_item = pairnext(&check_cursor))
- if ((check_item->da == vp->da)
- && (check_item->op != T_OP_SET)) {
- compare = paircmp(check_item, vp);
- if (compare == 1)
- pass++;
- else
- fail++;
- }
+ pid = fork();
+ if (pid < 0) {
+ exit(EXIT_FAILURE);
}
- if (fail == 0 && pass != 0) {
- /*
- * Cache authentication requests, as the replies
- * may not match the RADIUS filter.
- */
- if ((packet->code == PW_AUTHENTICATION_REQUEST) ||
- (packet->code == PW_ACCOUNTING_REQUEST)) {
- rbtree_deletebydata(filter_tree, packet);
-
- if (!rbtree_insert(filter_tree, packet)) {
- oom:
- fprintf(stderr, "radsniff: Out of memory\n");
- exit(1);
- }
- }
- return 0; /* matched */
+ /*
+ * Kill the parent...
+ */
+ if (pid > 0) {
+ close(self_pipe[0]);
+ close(self_pipe[1]);
+ exit(EXIT_SUCCESS);
}
/*
- * Don't create erroneous matches.
+ * Continue as the child.
*/
- if ((packet->code == PW_AUTHENTICATION_REQUEST) ||
- (packet->code == PW_ACCOUNTING_REQUEST)) {
- rbtree_deletebydata(filter_tree, packet);
- return 1;
+
+ /* Create a new SID for the child process */
+ sid = setsid();
+ if (sid < 0) {
+ exit(EXIT_FAILURE);
}
/*
- * Else see if a previous Access-Request
- * matched. If so, also print out the
- * matching accept, reject, or challenge.
+ * Change the current working directory. This prevents the current
+ * directory from being locked; hence not being able to remove it.
*/
- if ((packet->code == PW_AUTHENTICATION_ACK) ||
- (packet->code == PW_AUTHENTICATION_REJECT) ||
- (packet->code == PW_ACCESS_CHALLENGE) ||
- (packet->code == PW_ACCOUNTING_RESPONSE)) {
- RADIUS_PACKET *reply;
+ if ((chdir("/")) < 0) {
+ exit(EXIT_FAILURE);
+ }
- /*
- * This swaps the various fields.
- */
- reply = rad_alloc_reply(NULL, packet);
- if (!reply) goto oom;
+ /*
+ * And write it AFTER we've forked, so that we write the
+ * correct PID.
+ */
+ fp = fopen(pidfile, "w");
+ if (fp != NULL) {
+ fprintf(fp, "%d\n", (int) sid);
+ fclose(fp);
+ } else {
+ ERROR("Failed creating PID file %s: %s", pidfile, fr_syserror(errno));
+ exit(EXIT_FAILURE);
+ }
- compare = 1;
- if (rbtree_finddata(filter_tree, reply)) {
- compare = 0;
+ /*
+ * Close stdout and stderr if they've not been redirected.
+ */
+ if (isatty(fileno(stdout))) {
+ if (!freopen("/dev/null", "w", stdout)) {
+ exit(EXIT_FAILURE);
}
-
- rad_free(&reply);
- return compare;
}
- return 1;
+ if (isatty(fileno(stderr))) {
+ if (!freopen("/dev/null", "w", stderr)) {
+ exit(EXIT_FAILURE);
+ }
+ }
}
#define USEC 1000000
-static void tv_sub(struct timeval const *end, struct timeval const *start,
- struct timeval *elapsed)
+static void rs_tv_sub(struct timeval const *end, struct timeval const *start, struct timeval *elapsed)
{
elapsed->tv_sec = end->tv_sec - start->tv_sec;
if (elapsed->tv_sec > 0) {
}
}
-static void got_packet(UNUSED uint8_t *args, struct pcap_pkthdr const*header, uint8_t const *data)
+static void rs_tv_add_ms(struct timeval const *start, unsigned long interval, struct timeval *result) {
+ result->tv_sec = start->tv_sec + (interval / 1000);
+ result->tv_usec = start->tv_usec + ((interval % 1000) * 1000);
+
+ if (result->tv_usec > USEC) {
+ result->tv_usec -= USEC;
+ result->tv_sec++;
+ }
+}
+
+static void rs_time_print(char *out, size_t len, struct timeval const *t)
+{
+ size_t ret;
+ struct timeval now;
+ uint32_t usec;
+
+ if (!t) {
+ gettimeofday(&now, NULL);
+ t = &now;
+ }
+
+ ret = strftime(out, len, "%Y-%m-%d %H:%M:%S", localtime(&t->tv_sec));
+ if (ret >= len) {
+ return;
+ }
+
+ usec = t->tv_usec;
+
+ if (usec) {
+ while (usec < 100000) usec *= 10;
+ snprintf(out + ret, len - ret, ".%i", usec);
+ } else {
+ snprintf(out + ret, len - ret, ".000000");
+ }
+}
+
+static void rs_packet_print_null(UNUSED uint64_t count, UNUSED rs_status_t status, UNUSED fr_pcap_t *handle,
+ UNUSED RADIUS_PACKET *packet, UNUSED struct timeval *elapsed,
+ UNUSED struct timeval *latency, UNUSED bool response, UNUSED bool body)
+{
+ return;
+}
+
+static size_t rs_prints_csv(char *out, size_t outlen, char const *in, size_t inlen)
+{
+ char const *start = out;
+ uint8_t const *str = (uint8_t const *) in;
+
+ if (!in) {
+ if (outlen) {
+ *out = '\0';
+ }
+
+ return 0;
+ }
+
+ if (inlen == 0) {
+ inlen = strlen(in);
+ }
+
+ while ((inlen > 0) && (outlen > 2)) {
+ /*
+ * Escape double quotes with... MORE DOUBLE QUOTES!
+ */
+ if (*str == '"') {
+ *out++ = '"';
+ outlen--;
+ }
+
+ /*
+ * Safe chars which require no escaping
+ */
+ if ((*str == '\r') || (*str == '\n') || ((*str >= '\x20') && (*str <= '\x7E'))) {
+ *out++ = *str++;
+ outlen--;
+ inlen--;
+
+ continue;
+ }
+
+ /*
+ * Everything else is dropped
+ */
+ str++;
+ inlen--;
+ }
+ *out = '\0';
+
+ return out - start;
+}
+
+static void rs_packet_print_csv_header(void)
+{
+ char buffer[2048];
+ char *p = buffer;
+ int i;
+
+ ssize_t len, s = sizeof(buffer);
+
+ len = strlcpy(p, "\"Status\",\"Count\",\"Time\",\"Latency\",\"Type\",\"Interface\","
+ "\"Src IP\",\"Src Port\",\"Dst IP\",\"Dst Port\",\"ID\",", s);
+ p += len;
+ s -= len;
+
+ if (s <= 0) return;
+
+ for (i = 0; i < conf->list_da_num; i++) {
+ char const *in;
+
+ *p++ = '"';
+ s -= 1;
+ if (s <= 0) return;
+
+ for (in = conf->list_da[i]->name; *in; in++) {
+ *p++ = *in;
+ s -= len;
+ if (s <= 0) return;
+ }
+
+ *p++ = '"';
+ s -= 1;
+ if (s <= 0) return;
+ *p++ = ',';
+ s -= 1;
+ if (s <= 0) return;
+ }
+
+ *--p = '\0';
+
+ fprintf(stdout , "%s\n", buffer);
+}
+
+static void rs_packet_print_csv(uint64_t count, rs_status_t status, fr_pcap_t *handle, RADIUS_PACKET *packet,
+ UNUSED struct timeval *elapsed, struct timeval *latency, UNUSED bool response,
+ bool body)
+{
+ char const *status_str;
+ char buffer[2048];
+ char *p = buffer;
+
+ char src[INET6_ADDRSTRLEN];
+ char dst[INET6_ADDRSTRLEN];
+
+ ssize_t len, s = sizeof(buffer);
+
+ inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, src, sizeof(src));
+ inet_ntop(packet->dst_ipaddr.af, &packet->dst_ipaddr.ipaddr, dst, sizeof(dst));
+
+ status_str = fr_int2str(rs_events, status, NULL);
+ assert(status_str);
+
+ len = snprintf(p, s, "%s,%" PRIu64 ",%s,", status_str, count, timestr);
+ p += len;
+ s -= len;
+
+ if (s <= 0) return;
+
+ if (latency) {
+ len = snprintf(p, s, "%u.%03u,",
+ (unsigned int) latency->tv_sec, ((unsigned int) latency->tv_usec / 1000));
+ p += len;
+ s -= len;
+ } else {
+ *p = ',';
+ p += 1;
+ s -= 1;
+ }
+
+ if (s <= 0) return;
+
+ /* Status, Type, Interface, Src, Src port, Dst, Dst port, ID */
+ if (is_radius_code(packet->code)) {
+ len = snprintf(p, s, "%s,%s,%s,%i,%s,%i,%i,", fr_packet_codes[packet->code], handle->name,
+ src, packet->src_port, dst, packet->dst_port, packet->id);
+ } else {
+ len = snprintf(p, s, "%i,%s,%s,%i,%s,%i,%i,", packet->code, handle->name,
+ src, packet->src_port, dst, packet->dst_port, packet->id);
+ }
+ p += len;
+ s -= len;
+
+ if (s <= 0) return;
+
+ if (body) {
+ int i;
+ VALUE_PAIR *vp;
+
+ for (i = 0; i < conf->list_da_num; i++) {
+ vp = pairfind_da(packet->vps, conf->list_da[i], TAG_ANY);
+ if (vp && (vp->length > 0)) {
+ if (conf->list_da[i]->type == PW_TYPE_STRING) {
+ *p++ = '"';
+ s--;
+ if (s <= 0) return;
+
+ len = rs_prints_csv(p, s, vp->vp_strvalue, vp->length);
+ p += len;
+ s -= len;
+ if (s <= 0) return;
+
+ *p++ = '"';
+ s--;
+ if (s <= 0) return;
+ } else {
+ len = vp_prints_value(p, s, vp, 0);
+ p += len;
+ s -= len;
+ if (s <= 0) return;
+ }
+ }
+
+ *p++ = ',';
+ s -= 1;
+ if (s <= 0) return;
+ }
+ } else {
+ s -= conf->list_da_num;
+ if (s <= 0) return;
+
+ memset(p, ',', conf->list_da_num);
+ p += conf->list_da_num;
+ }
+
+ *--p = '\0';
+ fprintf(stdout , "%s\n", buffer);
+}
+
+static void rs_packet_print_fancy(uint64_t count, rs_status_t status, fr_pcap_t *handle, RADIUS_PACKET *packet,
+ struct timeval *elapsed, struct timeval *latency, bool response, bool body)
+{
+ char buffer[2048];
+ char *p = buffer;
+
+ char src[INET6_ADDRSTRLEN];
+ char dst[INET6_ADDRSTRLEN];
+
+ ssize_t len, s = sizeof(buffer);
+
+ inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, src, sizeof(src));
+ inet_ntop(packet->dst_ipaddr.af, &packet->dst_ipaddr.ipaddr, dst, sizeof(dst));
+
+ /* Only print out status str if something's not right */
+ if (status != RS_NORMAL) {
+ char const *status_str;
+
+ status_str = fr_int2str(rs_events, status, NULL);
+ assert(status_str);
+
+ len = snprintf(p, s, "** %s ** ", status_str);
+ p += len;
+ s -= len;
+ if (s <= 0) return;
+ }
+
+ if (is_radius_code(packet->code)) {
+ len = snprintf(p, s, "%s Id %i %s:%s:%d %s %s:%i ",
+ fr_packet_codes[packet->code],
+ packet->id,
+ handle->name,
+ response ? dst : src,
+ response ? packet->dst_port : packet->src_port,
+ response ? "<-" : "->",
+ response ? src : dst ,
+ response ? packet->src_port : packet->dst_port);
+ } else {
+ len = snprintf(p, s, "%i Id %i %s:%s:%i %s %s:%i ",
+ packet->code,
+ packet->id,
+ handle->name,
+ response ? dst : src,
+ response ? packet->dst_port : packet->src_port,
+ response ? "<-" : "->",
+ response ? src : dst ,
+ response ? packet->src_port : packet->dst_port);
+ }
+ p += len;
+ s -= len;
+ if (s <= 0) return;
+
+ if (elapsed) {
+ len = snprintf(p, s, "+%u.%03u ",
+ (unsigned int) elapsed->tv_sec, ((unsigned int) elapsed->tv_usec / 1000));
+ p += len;
+ s -= len;
+ if (s <= 0) return;
+ }
+
+ if (latency) {
+ len = snprintf(p, s, "+%u.%03u ",
+ (unsigned int) latency->tv_sec, ((unsigned int) latency->tv_usec / 1000));
+ p += len;
+ s -= len;
+ if (s <= 0) return;
+ }
+
+ *--p = '\0';
+
+ RIDEBUG("%s", buffer);
+
+ if (body) {
+ /*
+ * Print out verbose HEX output
+ */
+ if (conf->print_packet && (fr_debug_flag > 3)) {
+ rad_print_hex(packet);
+ }
+
+ if (conf->print_packet && (fr_debug_flag > 1)) {
+ char vector[(AUTH_VECTOR_LEN * 2) + 1];
+
+ if (packet->vps) {
+ pairsort(&packet->vps, attrtagcmp);
+ vp_printlist(fr_log_fp, packet->vps);
+ }
+
+ fr_bin2hex(vector, packet->vector, AUTH_VECTOR_LEN);
+ INFO("\tAuthenticator-Field = 0x%s", vector);
+ }
+ }
+}
+
+static void rs_stats_print(rs_latency_t *stats, PW_CODE code)
+{
+ int i;
+ bool have_rt = false;
+
+ for (i = 0; i <= RS_RETRANSMIT_MAX; i++) {
+ if (stats->interval.rt[i]) {
+ have_rt = true;
+ }
+ }
+
+ if (!stats->interval.received && !have_rt && !stats->interval.reused) {
+ return;
+ }
+
+ if (stats->interval.received || stats->interval.linked) {
+ INFO("%s counters:", fr_packet_codes[code]);
+ if (stats->interval.received > 0) {
+ INFO("\tTotal : %.3lf/s" , stats->interval.received);
+ }
+ }
+
+ if (stats->interval.linked > 0) {
+ INFO("\tLinked : %.3lf/s", stats->interval.linked);
+ INFO("\tUnlinked : %.3lf/s", stats->interval.unlinked);
+ INFO("%s latency:", fr_packet_codes[code]);
+ INFO("\tHigh : %.3lfms", stats->interval.latency_high);
+ INFO("\tLow : %.3lfms", stats->interval.latency_low);
+ INFO("\tAverage : %.3lfms", stats->interval.latency_average);
+ INFO("\tMA : %.3lfms", stats->latency_smoothed);
+ }
+
+ if (have_rt || stats->interval.lost || stats->interval.reused) {
+ INFO("%s retransmits & loss:", fr_packet_codes[code]);
+
+ if (stats->interval.lost) {
+ INFO("\tLost : %.3lf/s", stats->interval.lost);
+ }
+
+ if (stats->interval.reused) {
+ INFO("\tID Reused : %.3lf/s", stats->interval.reused);
+ }
+
+ for (i = 0; i <= RS_RETRANSMIT_MAX; i++) {
+ if (!stats->interval.rt[i]) {
+ continue;
+ }
+
+ if (i != RS_RETRANSMIT_MAX) {
+ INFO("\tRT (%i) : %.3lf/s", i, stats->interval.rt[i]);
+ } else {
+ INFO("\tRT (%i+) : %.3lf/s", i, stats->interval.rt[i]);
+ }
+ }
+ }
+}
+
+/** Query libpcap to see if it dropped any packets
+ *
+ * We need to check to see if libpcap dropped any packets and if it did, we need to stop stats output for long
+ * enough for inaccurate statistics to be cleared out.
+ *
+ * @param in pcap handle to check.
+ * @param interval time between checks (used for debug output)
+ * @return 0, no drops, -1 we couldn't check, -2 dropped because of buffer exhaustion, -3 dropped because of NIC.
+ */
+static int rs_check_pcap_drop(fr_pcap_t *in, int interval) {
+ int ret = 0;
+ struct pcap_stat pstats;
+
+ if (pcap_stats(in->handle, &pstats) != 0) {
+ ERROR("%s failed retrieving pcap stats: %s", in->name, pcap_geterr(in->handle));
+ return -1;
+ }
+
+ INFO("\t%s%*s: %.3lf/s", in->name, (int) (10 - strlen(in->name)), "",
+ ((double) (pstats.ps_recv - in->pstats.ps_recv)) / interval);
+
+ if (pstats.ps_drop - in->pstats.ps_drop > 0) {
+ ERROR("%s dropped %i packets: Buffer exhaustion", in->name, pstats.ps_drop - in->pstats.ps_drop);
+ ret = -2;
+ }
+
+ if (pstats.ps_ifdrop - in->pstats.ps_ifdrop > 0) {
+ ERROR("%s dropped %i packets: Interface", in->name, pstats.ps_ifdrop - in->pstats.ps_ifdrop);
+ ret = -3;
+ }
+
+ in->pstats = pstats;
+
+ return ret;
+}
+
+/** Update smoothed average
+ *
+ */
+static void rs_stats_process_latency(rs_latency_t *stats)
+{
+ /*
+ * If we didn't link any packets during this interval, we don't have a value to return.
+ * returning 0 is misleading as it would be like saying the latency had dropped to 0.
+ * We instead set NaN which libcollectd converts to a 'U' or unknown value.
+ *
+ * This will cause gaps in graphs, but is completely legitimate as we are missing data.
+ * This is unfortunately an effect of being just a passive observer.
+ */
+ if (stats->interval.linked_total == 0) {
+ double unk = strtod("NAN()", (char **) NULL);
+
+ stats->interval.latency_average = unk;
+ stats->interval.latency_high = unk;
+ stats->interval.latency_low = unk;
+
+ /*
+ * We've not yet been able to determine latency, so latency_smoothed is also NaN
+ */
+ if (stats->latency_smoothed_count == 0) {
+ stats->latency_smoothed = unk;
+ }
+ return;
+ }
+
+ if (stats->interval.linked_total && stats->interval.latency_total) {
+ stats->interval.latency_average = (stats->interval.latency_total / stats->interval.linked_total);
+ }
+
+ if (isnan(stats->latency_smoothed)) {
+ stats->latency_smoothed = 0;
+ }
+ if (stats->interval.latency_average > 0) {
+ stats->latency_smoothed_count++;
+ stats->latency_smoothed += ((stats->interval.latency_average - stats->latency_smoothed) /
+ ((stats->latency_smoothed_count < 100) ? stats->latency_smoothed_count : 100));
+ }
+}
+
+static void rs_stats_process_counters(rs_latency_t *stats)
+{
+ int i;
+
+ stats->interval.received = ((long double) stats->interval.received_total) / conf->stats.interval;
+ stats->interval.linked = ((long double) stats->interval.linked_total) / conf->stats.interval;
+ stats->interval.unlinked = ((long double) stats->interval.unlinked_total) / conf->stats.interval;
+ stats->interval.reused = ((long double) stats->interval.reused_total) / conf->stats.interval;
+ stats->interval.lost = ((long double) stats->interval.lost_total) / conf->stats.interval;
+
+ for (i = 0; i < RS_RETRANSMIT_MAX; i++) {
+ stats->interval.rt[i] = ((long double) stats->interval.rt_total[i]) / conf->stats.interval;
+ }
+}
+
+/** Process stats for a single interval
+ *
+ */
+static void rs_stats_process(void *ctx)
{
+ size_t i;
+ size_t rs_codes_len = (sizeof(rs_useful_codes) / sizeof(*rs_useful_codes));
+ fr_pcap_t *in_p;
+ rs_update_t *this = ctx;
+ rs_stats_t *stats = this->stats;
+ struct timeval now;
- static int count = 1; /* Packets seen */
+ gettimeofday(&now, NULL);
+
+ stats->intervals++;
+
+ INFO("######### Stats Iteration %i #########", stats->intervals);
/*
- * Define pointers for packet's attributes
+ * Verify that none of the pcap handles have dropped packets.
*/
- const struct ip_header *ip; /* The IP header */
- const struct udp_header *udp; /* The UDP header */
- const uint8_t *payload; /* Packet payload */
+ INFO("Interface capture rate:");
+ for (in_p = this->in;
+ in_p;
+ in_p = in_p->next) {
+ if (rs_check_pcap_drop(in_p, conf->stats.interval) < 0) {
+ ERROR("Muting stats for the next %i milliseconds", conf->stats.timeout);
+
+ rs_tv_add_ms(&now, conf->stats.timeout, &stats->quiet);
+ goto clear;
+ }
+ }
+
+ if ((stats->quiet.tv_sec + (stats->quiet.tv_usec / 1000000.0)) -
+ (now.tv_sec + (now.tv_usec / 1000000.0)) > 0) {
+ INFO("Stats muted because of warmup, or previous error");
+ goto clear;
+ }
/*
- * And define the size of the structures we're using
+ * Latency stats need a bit more work to calculate the SMA.
+ *
+ * No further work is required for codes.
*/
- int size_ethernet = sizeof(struct ethernet_header);
- int size_ip = sizeof(struct ip_header);
- int size_udp = sizeof(struct udp_header);
+ for (i = 0; i < rs_codes_len; i++) {
+ rs_stats_process_latency(&stats->exchange[rs_useful_codes[i]]);
+ rs_stats_process_counters(&stats->exchange[rs_useful_codes[i]]);
+ if (fr_debug_flag > 0) {
+ rs_stats_print(&stats->exchange[rs_useful_codes[i]], rs_useful_codes[i]);
+ }
+ }
+#ifdef HAVE_COLLECTDC_H
/*
- * For FreeRADIUS
+ * Update stats in collectd using the complex structures we
+ * initialised earlier.
*/
- RADIUS_PACKET *packet, *original;
- struct timeval elapsed;
+ if ((conf->stats.out == RS_STATS_OUT_COLLECTD) && conf->stats.handle) {
+ rs_stats_collectd_do_stats(conf, conf->stats.tmpl, &now);
+ }
+#endif
+ clear:
/*
- * Define our packet's attributes
+ * Rinse and repeat...
*/
+ for (i = 0; i < rs_codes_len; i++) {
+ memset(&stats->exchange[rs_useful_codes[i]].interval, 0,
+ sizeof(stats->exchange[rs_useful_codes[i]].interval));
+ }
- if ((data[0] == 2) && (data[1] == 0) &&
- (data[2] == 0) && (data[3] == 0)) {
- ip = (struct ip_header const *) (data + 4);
+ {
+ static fr_event_t *event;
- } else {
- ip = (struct ip_header const *)(data + size_ethernet);
+ now.tv_sec += conf->stats.interval;
+ now.tv_usec = 0;
+
+ if (!fr_event_insert(this->list, rs_stats_process, ctx, &now, &event)) {
+ ERROR("Failed inserting stats interval event");
+ }
}
+}
- udp = (struct udp_header const *)(((uint8_t const *) ip) + size_ip);
- payload = (uint8_t const *)(((uint8_t const *) udp) + size_udp);
- packet = rad_alloc(NULL, 0);
- if (!packet) {
- fprintf(stderr, "Out of memory\n");
- return;
- }
+/** Update latency statistics for request/response and forwarded packets
+ *
+ */
+static void rs_stats_update_latency(rs_latency_t *stats, struct timeval *latency)
+{
+ double lint;
- packet->src_ipaddr.af = AF_INET;
- packet->src_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_src.s_addr;
- packet->src_port = ntohs(udp->udp_sport);
- packet->dst_ipaddr.af = AF_INET;
- packet->dst_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_dst.s_addr;
- packet->dst_port = ntohs(udp->udp_dport);
+ stats->interval.linked_total++;
+ /* More useful is this in milliseconds */
+ lint = (latency->tv_sec + (latency->tv_usec / 1000000.0)) * 1000;
+ if (lint > stats->interval.latency_high) {
+ stats->interval.latency_high = lint;
+ }
+ if (!stats->interval.latency_low || (lint < stats->interval.latency_low)) {
+ stats->interval.latency_low = lint;
+ }
+ stats->interval.latency_total += lint;
- memcpy(&packet->data, &payload, sizeof(packet->data));
- packet->data_len = header->len - (payload - data);
+}
- if (!rad_packet_ok(packet, 0)) {
- DEBUG(log_dst, "Packet: %s\n", fr_strerror());
+/** Copy a subset of attributes from one list into the other
+ *
+ * Should be O(n) if all the attributes exist. List must be pre-sorted.
+ */
+static int rs_get_pairs(TALLOC_CTX *ctx, VALUE_PAIR **out, VALUE_PAIR *vps, DICT_ATTR const *da[], int num)
+{
+ vp_cursor_t list_cursor, out_cursor;
+ VALUE_PAIR *match, *last_match, *copy;
+ uint64_t count = 0;
+ int i;
+
+ last_match = vps;
+
+ fr_cursor_init(&list_cursor, &last_match);
+ fr_cursor_init(&out_cursor, out);
+ for (i = 0; i < num; i++) {
+ match = fr_cursor_next_by_da(&list_cursor, da[i], TAG_ANY);
+ if (!match) {
+ fr_cursor_init(&list_cursor, &last_match);
+ continue;
+ }
- DEBUG(log_dst, " From %s:%d\n", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport));
- DEBUG(log_dst, " To: %s:%d\n", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport));
- DEBUG(log_dst, " Type: %s\n", fr_packet_codes[packet->code]);
+ do {
+ copy = paircopyvp(ctx, match);
+ if (!copy) {
+ pairfree(out);
+ return -1;
+ }
+ fr_cursor_insert(&out_cursor, copy);
+ last_match = match;
- rad_free(&packet);
- return;
+ count++;
+ } while ((match = fr_cursor_next_by_da(&list_cursor, da[i], TAG_ANY)));
}
- switch (packet->code) {
- case PW_COA_REQUEST:
- /* we need a 16 x 0 byte vector for decrypting encrypted VSAs */
- original = nullpacket;
- break;
- case PW_AUTHENTICATION_ACK:
- /* look for a matching request and use it for decoding */
- original = rbtree_finddata(request_tree, packet);
- break;
- case PW_AUTHENTICATION_REQUEST:
- /* save the request for later matching */
- original = rad_alloc_reply(NULL, packet);
- if (original) { /* just ignore allocation failures */
- rbtree_deletebydata(request_tree, original);
- rbtree_insert(request_tree, original);
- }
- /* fallthrough */
- default:
- /* don't attempt to decode any encrypted attributes */
- original = NULL;
- }
+ return count;
+}
+static int _request_free(rs_request_t *request)
+{
/*
- * Decode the data without bothering to check the signatures.
+ * If were attempting to cleanup the request, and it's no longer in the request_tree
+ * something has gone very badly wrong.
*/
- if (rad_decode(packet, original, radius_secret) != 0) {
- rad_free(&packet);
- fr_perror("decode");
- return;
+ if (request->in_request_tree) {
+ assert(rbtree_deletebydata(request_tree, request));
}
- /*
- * We've seen a successful reply to this, so delete it now
- */
- if (original)
- rbtree_deletebydata(request_tree, original);
+ if (request->in_link_tree) {
+ assert(rbtree_deletebydata(link_tree, request));
+ }
- if (filter_vps && filter_packet(packet)) {
- rad_free(&packet);
- DEBUG(log_dst, "Packet number %d doesn't match\n", count++);
- return;
+ if (request->event) {
+ assert(fr_event_delete(events, &request->event));
}
- if (out) {
- pcap_dump((void *) out, header, data);
- goto check_filter;
+ rad_free(&request->packet);
+ rad_free(&request->expect);
+ rad_free(&request->linked);
+
+ return 0;
+}
+
+static void rs_packet_cleanup(rs_request_t *request)
+{
+
+ RADIUS_PACKET *packet = request->packet;
+ uint64_t count = request->id;
+
+ assert(request->stats_req);
+ assert(!request->rt_rsp || request->stats_rsp);
+ assert(packet);
+
+ /*
+ * Don't pollute stats or print spurious messages as radsniff closes.
+ */
+ if (cleanup) {
+ talloc_free(request);
+ return;
+ }
+
+ if (RIDEBUG_ENABLED()) {
+ rs_time_print(timestr, sizeof(timestr), &request->when);
+ }
+
+ /*
+ * Were at packet cleanup time which is when the packet was received + timeout
+ * and it's not been linked with a forwarded packet or a response.
+ *
+ * We now count it as lost.
+ */
+ if (!request->silent_cleanup) {
+ if (!request->linked) {
+ request->stats_req->interval.lost_total++;
+
+ if (conf->event_flags & RS_LOST) {
+ /* @fixme We should use flags in the request to indicate whether it's been dumped
+ * to a PCAP file or logged yet, this simplifies the body logging logic */
+ conf->logger(request->id, RS_LOST, request->in, packet, NULL, NULL, false,
+ conf->filter_response_vps || !(conf->event_flags & RS_NORMAL));
+ }
+ }
+
+ if (request->in->type == PCAP_INTERFACE_IN) {
+ RDEBUG("Cleaning up request packet ID %i", request->expect->id);
+ }
+ }
+
+ /*
+ * Now the request is done, we can update the retransmission stats
+ */
+ if (request->rt_req > RS_RETRANSMIT_MAX) {
+ request->stats_req->interval.rt_total[RS_RETRANSMIT_MAX]++;
+ } else {
+ request->stats_req->interval.rt_total[request->rt_req]++;
+ }
+
+ if (request->rt_rsp) {
+ if (request->rt_rsp > RS_RETRANSMIT_MAX) {
+ request->stats_rsp->interval.rt_total[RS_RETRANSMIT_MAX]++;
+ } else {
+ request->stats_rsp->interval.rt_total[request->rt_rsp]++;
+ }
+ }
+
+ talloc_free(request);
+}
+
+static void _rs_event(void *ctx)
+{
+ rs_request_t *request = talloc_get_type_abort(ctx, rs_request_t);
+ request->event = NULL;
+ rs_packet_cleanup(request);
+}
+
+/** Wrapper around fr_packet_cmp to strip off the outer request struct
+ *
+ */
+static int rs_packet_cmp(rs_request_t const *a, rs_request_t const *b)
+{
+ return fr_packet_cmp(a->expect, b->expect);
+}
+
+/* This is the same as immediately scheduling the cleanup event */
+#define RS_CLEANUP_NOW(_x, _s)\
+ {\
+ _x->silent_cleanup = _s;\
+ _x->when = header->ts;\
+ rs_packet_cleanup(_x);\
+ _x = NULL;\
+ } while (0)
+
+static void rs_packet_process(uint64_t count, rs_event_t *event, struct pcap_pkthdr const *header, uint8_t const *data)
+{
+ rs_stats_t *stats = event->stats;
+ struct timeval elapsed = {0, 0};
+ struct timeval latency;
+
+ /*
+ * Pointers into the packet data we just received
+ */
+ ssize_t len;
+ uint8_t const *p = data;
+
+ ip_header_t const *ip = NULL; /* The IP header */
+ ip_header6_t const *ip6 = NULL; /* The IPv6 header */
+ udp_header_t const *udp; /* The UDP header */
+ uint8_t version; /* IP header version */
+ bool response; /* Was it a response code */
+
+ decode_fail_t reason; /* Why we failed decoding the packet */
+ static uint64_t captured = 0;
+
+ rs_status_t status = RS_NORMAL; /* Any special conditions (RTX, Unlinked, ID-Reused) */
+ RADIUS_PACKET *current; /* Current packet were processing */
+ rs_request_t *original = NULL;
+
+ rs_request_t search;
+
+ memset(&search, 0, sizeof(search));
+
+ if (!start_pcap.tv_sec) {
+ start_pcap = header->ts;
+ }
+
+ if (RIDEBUG_ENABLED()) {
+ rs_time_print(timestr, sizeof(timestr), &header->ts);
+ }
+
+ len = fr_pcap_link_layer_offset(data, header->caplen, event->in->link_type);
+ if (len < 0) {
+ REDEBUG("Failed determining link layer header offset");
+ return;
+ }
+ p += len;
+
+ version = (p[0] & 0xf0) >> 4;
+ switch (version) {
+ case 4:
+ ip = (ip_header_t const *)p;
+ len = (0x0f & ip->ip_vhl) * 4; /* ip_hl specifies length in 32bit words */
+ p += len;
+ break;
+
+ case 6:
+ ip6 = (ip_header6_t const *)p;
+ p += sizeof(ip_header6_t);
+
+ break;
+
+ default:
+ REDEBUG("IP version invalid %i", version);
+ return;
+ }
+
+ /*
+ * End of variable length bits, do basic check now to see if packet looks long enough
+ */
+ len = (p - data) + sizeof(udp_header_t) + (sizeof(radius_packet_t) - 1); /* length value */
+ if ((size_t) len > header->caplen) {
+ REDEBUG("Packet too small, we require at least %zu bytes, captured %i bytes",
+ (size_t) len, header->caplen);
+ return;
+ }
+
+ /*
+ * UDP header validation.
+ */
+ udp = (udp_header_t const *)p;
+ {
+ uint16_t udp_len;
+ ssize_t diff;
+
+ udp_len = ntohs(udp->len);
+ diff = udp_len - (header->caplen - (p - data));
+ /* Truncated data */
+ if (diff > 0) {
+ REDEBUG("Packet too small by %zi bytes, UDP header + Payload should be %hu bytes",
+ diff, udp_len);
+ return;
+ }
+ /* Trailing data */
+ else if (diff < 0) {
+ REDEBUG("Packet too big by %zi bytes, UDP header + Payload should be %hu bytes",
+ diff * -1, udp_len);
+ return;
+ }
+ }
+ if ((version == 4) && conf->verify_udp_checksum) {
+ uint16_t expected;
+
+ expected = fr_udp_checksum((uint8_t const *) udp, ntohs(udp->len), udp->checksum,
+ ip->ip_src, ip->ip_dst);
+ if (udp->checksum != expected) {
+ REDEBUG("UDP checksum invalid, packet: 0x%04hx calculated: 0x%04hx",
+ ntohs(udp->checksum), ntohs(expected));
+ /* Not a fatal error */
+ }
+ }
+ p += sizeof(udp_header_t);
+
+ /*
+ * With artificial talloc memory limits there's a good chance we can
+ * recover once some requests timeout, so make an effort to deal
+ * with allocation failures gracefully.
+ */
+ current = rad_alloc(conf, 0);
+ if (!current) {
+ REDEBUG("Failed allocating memory to hold decoded packet");
+ rs_tv_add_ms(&header->ts, conf->stats.timeout, &stats->quiet);
+ return;
+ }
+
+ current->timestamp = header->ts;
+ current->data_len = header->caplen - (p - data);
+ memcpy(¤t->data, &p, sizeof(current->data));
+
+ /*
+ * Populate IP/UDP fields from PCAP data
+ */
+ if (ip) {
+ current->src_ipaddr.af = AF_INET;
+ current->src_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_src.s_addr;
+
+ current->dst_ipaddr.af = AF_INET;
+ current->dst_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_dst.s_addr;
+ } else {
+ current->src_ipaddr.af = AF_INET6;
+ memcpy(¤t->src_ipaddr.ipaddr.ip6addr.s6_addr, &ip6->ip_src.s6_addr,
+ sizeof(current->src_ipaddr.ipaddr.ip6addr.s6_addr));
+
+ current->dst_ipaddr.af = AF_INET6;
+ memcpy(¤t->dst_ipaddr.ipaddr.ip6addr.s6_addr, &ip6->ip_dst.s6_addr,
+ sizeof(current->dst_ipaddr.ipaddr.ip6addr.s6_addr));
+ }
+
+ current->src_port = ntohs(udp->src);
+ current->dst_port = ntohs(udp->dst);
+
+ if (!rad_packet_ok(current, 0, &reason)) {
+ REDEBUG("%s", fr_strerror());
+ if (conf->event_flags & RS_ERROR) {
+ conf->logger(count, RS_ERROR, event->in, current, &elapsed, NULL, false, false);
+ }
+ rad_free(¤t);
+
+ return;
+ }
+
+ switch (current->code) {
+ case PW_CODE_ACCOUNTING_RESPONSE:
+ case PW_CODE_AUTHENTICATION_REJECT:
+ case PW_CODE_AUTHENTICATION_ACK:
+ case PW_CODE_ACCESS_CHALLENGE:
+ case PW_CODE_COA_NAK:
+ case PW_CODE_COA_ACK:
+ case PW_CODE_DISCONNECT_NAK:
+ case PW_CODE_DISCONNECT_ACK:
+ case PW_CODE_STATUS_CLIENT:
+ {
+ /* look for a matching request and use it for decoding */
+ search.expect = current;
+ original = rbtree_finddata(request_tree, &search);
+
+ /*
+ * Verify this code is allowed
+ */
+ if (conf->filter_response_code && (conf->filter_response_code != current->code)) {
+ drop_response:
+ RDEBUG2("Response dropped by filter");
+ rad_free(¤t);
+
+ /* We now need to cleanup the original request too */
+ if (original) {
+ RS_CLEANUP_NOW(original, true);
+ }
+ return;
+ }
+
+ /*
+ * Only decode attributes if we want to print them or filter on them
+ * rad_packet_ok does checks to verify the packet is actually valid.
+ */
+ if (conf->decode_attrs) {
+ int ret;
+ FILE *log_fp = fr_log_fp;
+
+ fr_log_fp = NULL;
+ ret = rad_decode(current, original ? original->expect : NULL, conf->radius_secret);
+ fr_log_fp = log_fp;
+ if (ret != 0) {
+ rad_free(¤t);
+ REDEBUG("Failed decoding");
+ return;
+ }
+ }
+
+ /*
+ * Check if we've managed to link it to a request
+ */
+ if (original) {
+ /*
+ * Now verify the packet passes the attribute filter
+ */
+ if (conf->filter_response_vps) {
+ pairsort(¤t->vps, attrtagcmp);
+ if (!pairvalidate_relaxed(NULL, conf->filter_response_vps, current->vps)) {
+ goto drop_response;
+ }
+ }
+
+ /*
+ * Is this a retransmission?
+ */
+ if (original->linked) {
+ status = RS_RTX;
+ original->rt_rsp++;
+
+ rad_free(&original->linked);
+ fr_event_delete(event->list, &original->event);
+ /*
+ * ...nope it's the first response to a request.
+ */
+ } else {
+ original->stats_rsp = &stats->exchange[current->code];
+ }
+
+ /*
+ * Insert a callback to remove the request and response
+ * from the tree after the timeout period.
+ * The delay is so we can detect retransmissions.
+ */
+ original->linked = talloc_steal(original, current);
+ rs_tv_add_ms(&header->ts, conf->stats.timeout, &original->when);
+ if (!fr_event_insert(event->list, _rs_event, original, &original->when,
+ &original->event)) {
+ REDEBUG("Failed inserting new event");
+ /*
+ * Delete the original request/event, it's no longer valid
+ * for statistics.
+ */
+ talloc_free(original);
+ return;
+ }
+ /*
+ * No request seen, or request was dropped by attribute filter
+ */
+ } else {
+ /*
+ * If conf->filter_request_vps are set assume the original request was dropped,
+ * the alternative is maintaining another 'filter', but that adds
+ * complexity, reduces max capture rate, and is generally a PITA.
+ */
+ if (conf->filter_request) {
+ rad_free(¤t);
+ RDEBUG2("Original request dropped by filter");
+ return;
+ }
+
+ status = RS_UNLINKED;
+ stats->exchange[current->code].interval.unlinked_total++;
+ }
+
+ response = true;
+ break;
+ }
+
+ case PW_CODE_ACCOUNTING_REQUEST:
+ case PW_CODE_AUTHENTICATION_REQUEST:
+ case PW_CODE_COA_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ case PW_CODE_STATUS_SERVER:
+ {
+ /*
+ * Verify this code is allowed
+ */
+ if (conf->filter_request_code && (conf->filter_request_code != current->code)) {
+ drop_request:
+
+ RDEBUG2("Request dropped by filter");
+ rad_free(¤t);
+
+ return;
+ }
+
+ /*
+ * Only decode attributes if we want to print them or filter on them
+ * rad_packet_ok does checks to verify the packet is actually valid.
+ */
+ if (conf->decode_attrs) {
+ int ret;
+ FILE *log_fp = fr_log_fp;
+
+ fr_log_fp = NULL;
+ ret = rad_decode(current, NULL, conf->radius_secret);
+ fr_log_fp = log_fp;
+
+ if (ret != 0) {
+ rad_free(¤t);
+ REDEBUG("Failed decoding");
+ return;
+ }
+
+ pairsort(¤t->vps, attrtagcmp);
+ }
+
+ /*
+ * Save the request for later matching
+ */
+ search.expect = rad_alloc_reply(current, current);
+ if (!search.expect) {
+ REDEBUG("Failed allocating memory to hold expected reply");
+ rs_tv_add_ms(&header->ts, conf->stats.timeout, &stats->quiet);
+ rad_free(¤t);
+ return;
+ }
+ search.expect->code = current->code;
+
+ if ((conf->link_da_num > 0) && current->vps) {
+ int ret;
+ ret = rs_get_pairs(current, &search.link_vps, current->vps, conf->link_da,
+ conf->link_da_num);
+ if (ret < 0) {
+ ERROR("Failed extracting RTX linking pairs from request");
+ rad_free(¤t);
+ return;
+ }
+ }
+
+ /*
+ * If we have linking attributes set, attempt to find a request in the linking tree.
+ */
+ if (search.link_vps) {
+ rs_request_t *tuple;
+
+ original = rbtree_finddata(link_tree, &search);
+ tuple = rbtree_finddata(request_tree, &search);
+
+ /*
+ * If the packet we matched using attributes is not the same
+ * as the packet in the request tree, then we need to clean up
+ * the packet in the request tree.
+ */
+ if (tuple && (original != tuple)) {
+ RS_CLEANUP_NOW(tuple, true);
+ }
+ /*
+ * Detect duplicates using the normal 5-tuple of src/dst ips/ports id
+ */
+ } else {
+ original = rbtree_finddata(request_tree, &search);
+ if (original && memcmp(original->expect->vector, current->vector,
+ sizeof(original->expect->vector)) != 0) {
+ /*
+ * ID reused before the request timed out (which may be an issue)...
+ */
+ if (!original->linked) {
+ status = RS_REUSED;
+ stats->exchange[current->code].interval.reused_total++;
+ /* Occurs regularly downstream of proxy servers (so don't complain) */
+ RS_CLEANUP_NOW(original, true);
+ /*
+ * ...and before we saw a response (which may be a bigger issue).
+ */
+ } else {
+ RS_CLEANUP_NOW(original, false);
+ }
+ /* else it's a proper RTX with the same src/dst id authenticator/nonce */
+ }
+ }
+
+ /*
+ * Now verify the packet passes the attribute filter
+ */
+ if (conf->filter_request_vps) {
+ if (!pairvalidate_relaxed(NULL, conf->filter_request_vps, current->vps)) {
+ goto drop_request;
+ }
+ }
+
+ /*
+ * Is this a retransmission?
+ */
+ if (original) {
+ status = RS_RTX;
+ original->rt_req++;
+
+ rad_free(&original->packet);
+
+ /* We may of seen the response, but it may of been lost upstream */
+ rad_free(&original->linked);
+
+ original->packet = talloc_steal(original, current);
+
+ /* Request may need to be reinserted as the 5 tuple of the response may of changed */
+ if (rs_packet_cmp(original, &search) != 0) {
+ rbtree_deletebydata(request_tree, original);
+ }
+
+ rad_free(&original->expect);
+ original->expect = talloc_steal(original, search.expect);
+
+ /* Disarm the timer for the cleanup event for the original request */
+ fr_event_delete(event->list, &original->event);
+ /*
+ * ...nope it's a new request.
+ */
+ } else {
+ original = talloc_zero(conf, rs_request_t);
+ talloc_set_destructor(original, _request_free);
+
+ original->id = count;
+ original->in = event->in;
+ original->stats_req = &stats->exchange[current->code];
+
+ original->packet = talloc_steal(original, current);
+ original->expect = talloc_steal(original, search.expect);
+
+ if (search.link_vps) {
+ original->link_vps = pairsteal(original, search.link_vps);
+
+ /* We should never have conflicts */
+ assert(rbtree_insert(link_tree, original));
+ original->in_link_tree = true;
+ }
+
+ /*
+ * Special case for when were filtering by response,
+ * we never count any requests as lost, because we
+ * don't know what the response to that request would
+ * of been.
+ */
+ if (conf->filter_response_vps) {
+ original->silent_cleanup = true;
+ }
+ }
+
+ if (!original->in_request_tree) {
+ /* We should never have conflicts */
+ assert(rbtree_insert(request_tree, original));
+ original->in_request_tree = true;
+ }
+
+ /*
+ * Insert a callback to remove the request from the tree
+ */
+ original->packet->timestamp = header->ts;
+ rs_tv_add_ms(&header->ts, conf->stats.timeout, &original->when);
+ if (!fr_event_insert(event->list, _rs_event, original,
+ &original->when, &original->event)) {
+ REDEBUG("Failed inserting new event");
+
+ talloc_free(original);
+ return;
+ }
+ response = false;
+ break;
+ }
+
+ default:
+ REDEBUG("Unsupported code %i", current->code);
+ rad_free(¤t);
+
+ return;
+ }
+
+ if (event->out) {
+ pcap_dump((void *) (event->out->dumper), header, data);
+ }
+
+ rs_tv_sub(&header->ts, &start_pcap, &elapsed);
+
+ /*
+ * Increase received count
+ */
+ stats->exchange[current->code].interval.received_total++;
+
+ /*
+ * It's a linked response
+ */
+ if (original && original->linked) {
+ rs_tv_sub(¤t->timestamp, &original->packet->timestamp, &latency);
+
+ /*
+ * Update stats for both the request and response types.
+ *
+ * This isn't useful for things like Access-Requests, but will be useful for
+ * CoA and Disconnect Messages, as we get the average latency across both
+ * response types.
+ *
+ * It also justifies allocating PW_CODE_MAX instances of rs_latency_t.
+ */
+ rs_stats_update_latency(&stats->exchange[current->code], &latency);
+ rs_stats_update_latency(&stats->exchange[original->expect->code], &latency);
+
+ /*
+ * Were filtering on response, now print out the full data from the request
+ */
+ if (conf->filter_response && RIDEBUG_ENABLED() && (conf->event_flags & RS_NORMAL)) {
+ rs_time_print(timestr, sizeof(timestr), &original->packet->timestamp);
+ rs_tv_sub(&original->packet->timestamp, &start_pcap, &elapsed);
+ conf->logger(original->id, RS_NORMAL, original->in, original->packet, &elapsed, NULL, false, true);
+ rs_tv_sub(&header->ts, &start_pcap, &elapsed);
+ rs_time_print(timestr, sizeof(timestr), &header->ts);
+ }
+
+ if (conf->event_flags & status) {
+ conf->logger(count, status, event->in, current, &elapsed, &latency, response, true);
+ }
+ /*
+ * It's the original request
+ *
+ * If were filtering on responses we can only indicate we received it on response, or timeout.
+ */
+ } else if (!conf->filter_response && (conf->event_flags & status)) {
+ conf->logger(original ? original->id : count, status, event->in,
+ current, &elapsed, NULL, response, true);
+ }
+
+ fflush(fr_log_fp);
+
+ /*
+ * If it's a unlinked response, we need to free it explicitly, as it will
+ * not be done by the event queue.
+ */
+ if (response && !original) {
+ rad_free(¤t);
+ }
+
+ captured++;
+ /*
+ * We've hit our capture limit, break out of the event loop
+ */
+ if ((conf->limit > 0) && (captured >= conf->limit)) {
+ INFO("Captured %" PRIu64 " packets, exiting...", captured);
+ fr_event_loop_exit(events, 1);
+ }
+}
+
+static void rs_got_packet(UNUSED fr_event_list_t *el, int fd, void *ctx)
+{
+ static uint64_t count = 0; /* Packets seen */
+ rs_event_t *event = ctx;
+ pcap_t *handle = event->in->handle;
+
+ int i;
+ int ret;
+ const uint8_t *data;
+ struct pcap_pkthdr *header;
+
+ /*
+ * Consume entire capture, interleaving not currently possible
+ */
+ if ((event->in->type == PCAP_FILE_IN) || (event->in->type == PCAP_STDIO_IN)) {
+ while (!fr_event_loop_exiting(el)) {
+ struct timeval now;
+
+ ret = pcap_next_ex(handle, &header, &data);
+ if (ret == 0) {
+ /* No more packets available at this time */
+ return;
+ }
+ if (ret == -2) {
+ DEBUG("Done reading packets (%s)", event->in->name);
+ fr_event_fd_delete(events, 0, fd);
+
+ /* Signal pipe takes one slot which is why this is == 1 */
+ if (fr_event_list_num_fds(events) == 1) {
+ fr_event_loop_exit(events, 1);
+ }
+
+ return;
+ }
+ if (ret < 0) {
+ ERROR("Error requesting next packet, got (%i): %s", ret, pcap_geterr(handle));
+ return;
+ }
+
+ do {
+ now = header->ts;
+ } while (fr_event_run(el, &now) == 1);
+ count++;
+
+ rs_packet_process(count, event, header, data);
+ }
+ return;
+ }
+
+ /*
+ * Consume multiple packets from the capture buffer.
+ * We occasionally need to yield to allow events to run.
+ */
+ for (i = 0; i < RS_FORCE_YIELD; i++) {
+ ret = pcap_next_ex(handle, &header, &data);
+ if (ret == 0) {
+ /* No more packets available at this time */
+ return;
+ }
+ if (ret < 0) {
+ ERROR("Error requesting next packet, got (%i): %s", ret, pcap_geterr(handle));
+ return;
+ }
+
+ count++;
+ rs_packet_process(count, event, header, data);
+ }
+}
+
+static void _rs_event_status(struct timeval *wake)
+{
+ if (wake && ((wake->tv_sec != 0) || (wake->tv_usec >= 100000))) {
+ DEBUG2("Waking up in %d.%01u seconds.", (int) wake->tv_sec, (unsigned int) wake->tv_usec / 100000);
+
+ if (RIDEBUG_ENABLED()) {
+ rs_time_print(timestr, sizeof(timestr), wake);
+ }
+ }
+}
+
+/** Compare requests using packet info and lists of attributes
+ *
+ */
+static int rs_rtx_cmp(rs_request_t const *a, rs_request_t const *b)
+{
+ int rcode;
+
+ assert(a->link_vps);
+ assert(b->link_vps);
+
+ rcode = (int) a->expect->code - (int) b->expect->code;
+ if (rcode != 0) return rcode;
+
+ rcode = a->expect->sockfd - b->expect->sockfd;
+ if (rcode != 0) return rcode;
+
+ rcode = fr_ipaddr_cmp(&a->expect->src_ipaddr, &b->expect->src_ipaddr);
+ if (rcode != 0) return rcode;
+
+ rcode = fr_ipaddr_cmp(&a->expect->dst_ipaddr, &b->expect->dst_ipaddr);
+ if (rcode != 0) return rcode;
+
+ return pairlistcmp(a->link_vps, b->link_vps);
+}
+
+static int rs_build_dict_list(DICT_ATTR const **out, size_t len, char *list)
+{
+ size_t i = 0;
+ char *p, *tok;
+
+ p = list;
+ while ((tok = strsep(&p, "\t ,")) != NULL) {
+ DICT_ATTR const *da;
+ if ((*tok == '\t') || (*tok == ' ') || (*tok == '\0')) {
+ continue;
+ }
+
+ if (i == len) {
+ ERROR("Too many attributes, maximum allowed is %zu", len);
+ return -1;
+ }
+
+ da = dict_attrbyname(tok);
+ if (!da) {
+ ERROR("Error parsing attribute name \"%s\"", tok);
+ return -1;
+ }
+
+ out[i] = da;
+ i++;
+ }
+
+ /*
+ * This allows efficient list comparisons later
+ */
+ if (i > 1) fr_quick_sort((void const **)out, 0, i - 1, fr_pointer_cmp);
+
+ return i;
+}
+
+static int rs_build_filter(VALUE_PAIR **out, char const *filter)
+{
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+ FR_TOKEN code;
+
+ code = userparse(conf, filter, out);
+ if (code == T_OP_INVALID) {
+ ERROR("Invalid RADIUS filter \"%s\" (%s)", filter, fr_strerror());
+ return -1;
+ }
+
+ if (!*out) {
+ ERROR("Empty RADIUS filter '%s'", filter);
+ return -1;
+ }
+
+ for (vp = fr_cursor_init(&cursor, out);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ /*
+ * xlat expansion isn't support here
+ */
+ if (vp->type == VT_XLAT) {
+ vp->type = VT_DATA;
+ vp->vp_strvalue = vp->value.xlat;
+ }
}
- INFO(log_dst, "%s Id %d\t", fr_packet_codes[packet->code], packet->id);
-
/*
- * Print the RADIUS packet
+ * This allows efficient list comparisons later
*/
- INFO(log_dst, "%s:%d -> ", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport));
- INFO(log_dst, "%s:%d", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport));
+ pairsort(out, attrtagcmp);
- DEBUG1(log_dst, "\t(%d packets)", count++);
+ return 0;
+}
- if (!start_pcap.tv_sec) {
- start_pcap = header->ts;
- }
+static int rs_build_event_flags(int *flags, FR_NAME_NUMBER const *map, char *list)
+{
+ size_t i = 0;
+ char *p, *tok;
- tv_sub(&header->ts, &start_pcap, &elapsed);
+ p = list;
+ while ((tok = strsep(&p, "\t ,")) != NULL) {
+ int flag;
- INFO(log_dst, "\t+%u.%03u", (unsigned int) elapsed.tv_sec,
- (unsigned int) elapsed.tv_usec / 1000);
+ if ((*tok == '\t') || (*tok == ' ') || (*tok == '\0')) {
+ continue;
+ }
- if (fr_debug_flag > 1) {
- DEBUG(log_dst, "\n");
- if (packet->vps) {
- if (do_sort) {
- pairsort(&packet->vps, true);
- }
- vp_printlist(log_dst, packet->vps);
- pairfree(&packet->vps);
+ *flags |= flag = fr_str2int(map, tok, -1);
+ if (flag < 0) {
+ ERROR("Invalid flag \"%s\"", tok);
+ return -1;
}
+
+ i++;
}
- INFO(log_dst, "\n");
+ return i;
+}
+
+/** Callback for when the request is removed from the request tree
+ *
+ * @param request being removed.
+ */
+static void _unmark_request(void *request)
+{
+ rs_request_t *this = request;
+ this->in_request_tree = false;
+}
+
+/** Callback for when the request is removed from the link tree
+ *
+ * @param request being removed.
+ */
+static void _unmark_link(void *request)
+{
+ rs_request_t *this = request;
+ this->in_link_tree = false;
+}
+
+#ifdef HAVE_COLLECTDC_H
+/** Re-open the collectd socket
+ *
+ */
+static void rs_collectd_reopen(void *ctx)
+{
+ fr_event_list_t *list = ctx;
+ static fr_event_t *event;
+ struct timeval now, when;
- if (!to_stdout && (fr_debug_flag > 4)) {
- rad_print_hex(packet);
+ if (rs_stats_collectd_open(conf) == 0) {
+ DEBUG2("Stats output socket (re)opened");
+ return;
}
- fflush(log_dst);
+ ERROR("Will attempt to re-establish connection in %i ms", RS_SOCKET_REOPEN_DELAY);
- check_filter:
- /*
- * If we're doing filtering, Access-Requests are cached in the
- * filter tree.
- */
- if (!filter_vps ||
- ((packet->code != PW_AUTHENTICATION_REQUEST) &&
- (packet->code != PW_ACCOUNTING_REQUEST))) {
- rad_free(&packet);
+ gettimeofday(&now, NULL);
+ rs_tv_add_ms(&now, RS_SOCKET_REOPEN_DELAY, &when);
+ if (!fr_event_insert(list, rs_collectd_reopen, list, &when, &event)) {
+ ERROR("Failed inserting re-open event");
+ assert(0);
}
}
+#endif
+/** Write the last signal to the signal pipe
+ *
+ * @param sig raised
+ */
+static void rs_signal_self(int sig)
+{
+ if (write(self_pipe[1], &sig, sizeof(sig)) < 0) {
+ ERROR("Failed writing signal %s to pipe: %s", strsignal(sig), fr_syserror(errno));
+ exit(EXIT_FAILURE);
+ }
+}
-/** Wrapper function to allow rad_free to be called as an rbtree destructor callback
+/** Read the last signal from the signal pipe
*
- * @param packet to free.
*/
-static void _rb_rad_free(void *packet)
+static void rs_signal_action(UNUSED fr_event_list_t *list, int fd, UNUSED void *ctx)
{
- rad_free((RADIUS_PACKET **) &packet);
+ int sig;
+ ssize_t ret;
+
+ ret = read(fd, &sig, sizeof(sig));
+ if (ret < 0) {
+ ERROR("Failed reading signal from pipe: %s", fr_syserror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (ret != sizeof(sig)) {
+ ERROR("Failed reading signal from pipe: "
+ "Expected signal to be %zu bytes but only read %zu byes", sizeof(sig), ret);
+ exit(EXIT_FAILURE);
+ }
+
+ switch (sig) {
+#ifdef HAVE_COLLECTDC_H
+ case SIGPIPE:
+ rs_collectd_reopen(list);
+ break;
+#endif
+
+ case SIGINT:
+ case SIGTERM:
+ case SIGQUIT:
+ DEBUG2("Signalling event loop to exit");
+ fr_event_loop_exit(events, 1);
+ break;
+
+ default:
+ ERROR("Unhandled signal %s", strsignal(sig));
+ exit(EXIT_FAILURE);
+ }
}
static void NEVER_RETURNS usage(int status)
{
FILE *output = status ? stderr : stdout;
- fprintf(output, "Usage: radsniff [options]\n");
+ fprintf(output, "Usage: radsniff [options][stats options] -- [pcap files]\n");
fprintf(output, "options:\n");
- fprintf(output, " -c <count> Number of packets to capture.\n");
- fprintf(output, " -d <directory> Set dictionary directory.\n");
- fprintf(output, " -F Filter PCAP file from stdin to stdout.\n");
- fprintf(output, " -f <filter> PCAP filter (default is 'udp port <port> or <port + 1> or 3799')\n");
- fprintf(output, " -h This help message.\n");
- fprintf(output, " -i <interface> Capture packets from interface (defaults to any if supported).\n");
- fprintf(output, " -I <file> Read packets from file (overrides input of -F).\n");
- fprintf(output, " -p <port> Filter packets by port (default is 1812).\n");
- fprintf(output, " -q Print less debugging information.\n");
- fprintf(output, " -r <filter> RADIUS attribute filter.\n");
- fprintf(output, " -s <secret> RADIUS secret.\n");
- fprintf(output, " -S Sort attributes in the packet (useful for diffing responses).\n");
- fprintf(output, " -v Show program version information.\n");
- fprintf(output, " -w <file> Write output packets to file (overrides output of -F).\n");
- fprintf(output, " -x Print more debugging information (defaults to -xx).\n");
+ fprintf(output, " -a List all interfaces available for capture.\n");
+ fprintf(output, " -c <count> Number of packets to capture.\n");
+ fprintf(output, " -C Enable UDP checksum validation.\n");
+ fprintf(output, " -d <directory> Set dictionary directory.\n");
+ fprintf(output, " -d <raddb> Set configuration directory (defaults to " RADDBDIR ").\n");
+ fprintf(output, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
+ fprintf(output, " -e <event>[,<event>] Only log requests with these event flags.\n");
+ fprintf(output, " Event may be one of the following:\n");
+ fprintf(output, " - received - a request or response.\n");
+ fprintf(output, " - norsp - seen for a request.\n");
+ fprintf(output, " - rtx - of a request that we've seen before.\n");
+ fprintf(output, " - noreq - could be matched with the response.\n");
+ fprintf(output, " - reused - ID too soon.\n");
+ fprintf(output, " - error - decoding the packet.\n");
+ fprintf(output, " -f <filter> PCAP filter (default is 'udp port <port> or <port + 1> or 3799')\n");
+ fprintf(output, " -h This help message.\n");
+ fprintf(output, " -i <interface> Capture packets from interface (defaults to all if supported).\n");
+ fprintf(output, " -I <file> Read packets from file (overrides input of -F).\n");
+ fprintf(output, " -l <attr>[,<attr>] Output packet sig and a list of attributes.\n");
+ fprintf(output, " -L <attr>[,<attr>] Detect retransmissions using these attributes to link requests.\n");
+ fprintf(output, " -m Don't put interface(s) into promiscuous mode.\n");
+ fprintf(output, " -p <port> Filter packets by port (default is 1812).\n");
+ fprintf(output, " -P <pidfile> Daemonize and write out <pidfile>.\n");
+ fprintf(output, " -q Print less debugging information.\n");
+ fprintf(output, " -r <filter> RADIUS attribute request filter.\n");
+ fprintf(output, " -R <filter> RADIUS attribute response filter.\n");
+ fprintf(output, " -s <secret> RADIUS secret.\n");
+ fprintf(output, " -S Write PCAP data to stdout.\n");
+ fprintf(output, " -v Show program version information.\n");
+ fprintf(output, " -w <file> Write output packets to file.\n");
+ fprintf(output, " -x Print more debugging information.\n");
+ fprintf(output, "stats options:\n");
+ fprintf(output, " -W <interval> Periodically write out statistics every <interval> seconds.\n");
+ fprintf(output, " -T <timeout> How many milliseconds before the request is counted as lost "
+ "(defaults to %i).\n", RS_DEFAULT_TIMEOUT);
+#ifdef HAVE_COLLECTDC_H
+ fprintf(output, " -N <prefix> The instance name passed to the collectd plugin.\n");
+ fprintf(output, " -O <server> Write statistics to this collectd server.\n");
+#endif
exit(status);
}
int main(int argc, char *argv[])
{
- char const *from_dev = NULL; /* Capture from device */
- char const *from_file = NULL; /* Read from pcap file */
- int from_stdin = 0; /* Read from stdin */
+ fr_pcap_t *in = NULL, *in_p;
+ fr_pcap_t **in_head = ∈
+ fr_pcap_t *out = NULL;
- pcap_t *in = NULL; /* PCAP input handle */
-
- int limit = -1; /* How many packets to sniff */
+ int ret = 1; /* Exit status */
char errbuf[PCAP_ERRBUF_SIZE]; /* Error buffer */
-
- char *to_file = NULL; /* PCAP output file */
-
- char *pcap_filter = NULL; /* PCAP filter string */
- char *radius_filter = NULL;
int port = 1812;
- struct bpf_program fp; /* Holds compiled filter */
- bpf_u_int32 ip_mask = PCAP_NETMASK_UNKNOWN; /* Device Subnet mask */
- bpf_u_int32 ip_addr = 0; /* Device IP */
-
char buffer[1024];
int opt;
- FR_TOKEN parsecode;
- char const *radius_dir = RADIUS_DIR;
+ char const *radius_dir = RADDBDIR;
+ char const *dict_dir = DICTDIR;
- fr_debug_flag = 2;
- log_dst = stdout;
+ rs_stats_t stats;
+
+ fr_debug_flag = 1;
+ fr_log_fp = stdout;
+
+ /*
+ * Useful if using radsniff as a long running stats daemon
+ */
+#ifndef NDEBUG
+ if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
+ fr_perror("radsniff");
+ exit(EXIT_FAILURE);
+ }
+#endif
talloc_set_log_stderr();
+ conf = talloc_zero(NULL, rs_t);
+ if (!fr_assert(conf)) {
+ exit (1);
+ }
+
+ /*
+ * We don't really want probes taking down machines
+ */
+#ifdef HAVE_TALLOC_SET_MEMLIMIT
+ /*
+ * @fixme causes hang in talloc steal
+ */
+ //talloc_set_memlimit(conf, 524288000); /* 50 MB */
+#endif
+
+ /*
+ * Set some defaults
+ */
+ conf->print_packet = true;
+ conf->limit = 0;
+ conf->promiscuous = true;
+#ifdef HAVE_COLLECTDC_H
+ conf->stats.prefix = RS_DEFAULT_PREFIX;
+#endif
+ conf->radius_secret = RS_DEFAULT_SECRET;
+ conf->logger = rs_packet_print_null;
+
+#ifdef HAVE_COLLECTDC_H
+ conf->stats.prefix = RS_DEFAULT_PREFIX;
+#endif
+
/*
* Get options
*/
- while ((opt = getopt(argc, argv, "c:d:Ff:hi:I:p:qr:s:Svw:xX")) != EOF) {
+ while ((opt = getopt(argc, argv, "ab:c:Cd:D:e:Ff:hi:I:l:L:mp:P:qr:R:s:Svw:xXW:T:P:N:O:")) != EOF) {
switch (opt) {
+ case 'a':
+ {
+ pcap_if_t *all_devices = NULL;
+ pcap_if_t *dev_p;
+
+ if (pcap_findalldevs(&all_devices, errbuf) < 0) {
+ ERROR("Error getting available capture devices: %s", errbuf);
+ goto finish;
+ }
+
+ int i = 1;
+ for (dev_p = all_devices;
+ dev_p;
+ dev_p = dev_p->next) {
+ INFO("%i.%s", i++, dev_p->name);
+ }
+ ret = 0;
+ goto finish;
+ }
+
+ /* super secret option */
+ case 'b':
+ conf->buffer_pkts = atoi(optarg);
+ if (conf->buffer_pkts == 0) {
+ ERROR("Invalid buffer length \"%s\"", optarg);
+ usage(1);
+ }
+ break;
+
case 'c':
- limit = atoi(optarg);
- if (limit <= 0) {
- fprintf(stderr, "radsniff: Invalid number of packets \"%s\"\n", optarg);
- exit(1);
+ conf->limit = atoi(optarg);
+ if (conf->limit == 0) {
+ ERROR("Invalid number of packets \"%s\"", optarg);
+ usage(1);
}
break;
+
+ /* udp checksum */
+ case 'C':
+ conf->verify_udp_checksum = true;
+ break;
+
case 'd':
radius_dir = optarg;
break;
- case 'F':
- from_stdin = 1;
- to_stdout = 1;
+
+ case 'D':
+ dict_dir = optarg;
+ break;
+
+ case 'e':
+ if (rs_build_event_flags((int *) &conf->event_flags, rs_events, optarg) < 0) {
+ usage(64);
+ }
break;
+
case 'f':
- pcap_filter = optarg;
+ conf->pcap_filter = optarg;
break;
+
case 'h':
usage(0);
break;
+
case 'i':
- from_dev = optarg;
+ *in_head = fr_pcap_init(conf, optarg, PCAP_INTERFACE_IN);
+ if (!*in_head) {
+ goto finish;
+ }
+ in_head = &(*in_head)->next;
+ conf->from_dev = true;
break;
+
case 'I':
- from_file = optarg;
+ *in_head = fr_pcap_init(conf, optarg, PCAP_FILE_IN);
+ if (!*in_head) {
+ goto finish;
+ }
+ in_head = &(*in_head)->next;
+ conf->from_file = true;
+ break;
+
+ case 'l':
+ conf->list_attributes = optarg;
+ break;
+
+ case 'L':
+ conf->link_attributes = optarg;
+ break;
+
+ case 'm':
+ conf->promiscuous = false;
break;
+
case 'p':
port = atoi(optarg);
break;
+
+ case 'P':
+ conf->daemonize = true;
+ conf->pidfile = optarg;
+ break;
+
case 'q':
if (fr_debug_flag > 0) {
fr_debug_flag--;
}
break;
+
case 'r':
- radius_filter = optarg;
+ conf->filter_request = optarg;
break;
+
+ case 'R':
+ conf->filter_response = optarg;
+ break;
+
case 's':
- radius_secret = optarg;
+ conf->radius_secret = optarg;
break;
+
case 'S':
- do_sort = 1;
+ conf->to_stdout = true;
break;
+
case 'v':
- INFO(log_dst, "%s %s\n", radsniff_version, pcap_lib_version());
- exit(0);
+#ifdef HAVE_COLLECTDC_H
+ INFO("%s, %s, collectdclient version %s", radsniff_version, pcap_lib_version(),
+ lcc_version_string());
+#else
+ INFO("%s %s", radsniff_version, pcap_lib_version());
+#endif
+ exit(EXIT_SUCCESS);
break;
+
case 'w':
- to_file = optarg;
+ out = fr_pcap_init(conf, optarg, PCAP_FILE_OUT);
+ if (!out) {
+ ERROR("Failed creating pcap file \"%s\"", optarg);
+ exit(EXIT_FAILURE);
+ }
+ conf->to_file = true;
break;
+
case 'x':
case 'X':
- fr_debug_flag++;
+ fr_debug_flag++;
+ break;
+
+ case 'W':
+ conf->stats.interval = atoi(optarg);
+ conf->print_packet = false;
+ if (conf->stats.interval <= 0) {
+ ERROR("Stats interval must be > 0");
+ usage(64);
+ }
+ break;
+
+ case 'T':
+ conf->stats.timeout = atoi(optarg);
+ if (conf->stats.timeout <= 0) {
+ ERROR("Timeout value must be > 0");
+ usage(64);
+ }
+ break;
+
+#ifdef HAVE_COLLECTDC_H
+ case 'N':
+ conf->stats.prefix = optarg;
+ break;
+
+ case 'O':
+ conf->stats.collectd = optarg;
+ conf->stats.out = RS_STATS_OUT_COLLECTD;
break;
+#endif
default:
usage(64);
}
}
+ /*
+ * Mismatch between the binary and the libraries it depends on
+ */
+ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
+ fr_perror("radsniff");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Useful for file globbing */
+ while (optind < argc) {
+ *in_head = fr_pcap_init(conf, argv[optind], PCAP_FILE_IN);
+ if (!*in_head) {
+ goto finish;
+ }
+ in_head = &(*in_head)->next;
+ conf->from_file = true;
+ optind++;
+ }
+
+ /* Is stdin not a tty? If so it's probably a pipe */
+ if (!isatty(fileno(stdin))) {
+ conf->from_stdin = true;
+ }
+
/* What's the point in specifying -F ?! */
- if (from_stdin && from_file && to_file) {
+ if (conf->from_stdin && conf->from_file && conf->to_file) {
usage(64);
}
/* Can't read from both... */
- if (from_file && from_dev) {
+ if (conf->from_file && conf->from_dev) {
usage(64);
}
/* Reading from file overrides stdin */
- if (from_stdin && (from_file || from_dev)) {
- from_stdin = 0;
+ if (conf->from_stdin && (conf->from_file || conf->from_dev)) {
+ conf->from_stdin = false;
}
/* Writing to file overrides stdout */
- if (to_file && to_stdout) {
- to_stdout = 0;
+ if (conf->to_file && conf->to_stdout) {
+ conf->to_stdout = false;
+ }
+
+ if (conf->to_stdout) {
+ out = fr_pcap_init(conf, "stdout", PCAP_STDIO_OUT);
+ if (!out) {
+ goto finish;
+ }
+ }
+
+ if (conf->from_stdin) {
+ *in_head = fr_pcap_init(conf, "stdin", PCAP_STDIO_IN);
+ if (!*in_head) {
+ goto finish;
+ }
+ in_head = &(*in_head)->next;
+ }
+
+ if (conf->stats.interval && !conf->stats.out) {
+ conf->stats.out = RS_STATS_OUT_STDIO;
+ }
+
+ if (conf->stats.timeout == 0) {
+ conf->stats.timeout = RS_DEFAULT_TIMEOUT;
}
/*
- * If were writing pcap data stdout we *really* don't want to send
- * logging there as well.
+ * If were writing pcap data, or CSV to stdout we *really* don't want to send
+ * logging there as well.
*/
- log_dst = to_stdout ? stderr : stdout;
+ if (conf->to_stdout || conf->list_attributes) {
+ fr_log_fp = stderr;
+ }
+
+ if (conf->list_attributes) {
+ conf->logger = rs_packet_print_csv;
+ } else if (fr_debug_flag > 0) {
+ conf->logger = rs_packet_print_fancy;
+ }
#if !defined(HAVE_PCAP_FOPEN_OFFLINE) || !defined(HAVE_PCAP_DUMP_FOPEN)
- if (from_stdin || to_stdout) {
- fprintf(stderr, "radsniff: PCAP streams not supported.\n");
- exit(64);
+ if (conf->from_stdin || conf->to_stdout) {
+ ERROR("PCAP streams not supported");
+ goto finish;
}
#endif
- if (!pcap_filter) {
- pcap_filter = buffer;
+ if (!conf->pcap_filter) {
snprintf(buffer, sizeof(buffer), "udp port %d or %d or %d",
port, port + 1, 3799);
+ conf->pcap_filter = buffer;
}
- /*
- * There are times when we don't need the dictionaries.
- */
- if (!to_stdout) {
- if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) {
- fr_perror("radsniff");
- exit(64);
+ if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) {
+ fr_perror("radsniff");
+ ret = 64;
+ goto finish;
+ }
+
+ if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) {
+ fr_perror("radsniff");
+ ret = 64;
+ goto finish;
+ }
+
+ fr_strerror(); /* Clear out any non-fatal errors */
+
+ if (conf->list_attributes) {
+ conf->list_da_num = rs_build_dict_list(conf->list_da, sizeof(conf->list_da) / sizeof(*conf->list_da),
+ conf->list_attributes);
+ if (conf->list_da_num < 0) {
+ usage(64);
+ }
+ rs_packet_print_csv_header();
+ }
+
+ if (conf->link_attributes) {
+ conf->link_da_num = rs_build_dict_list(conf->link_da, sizeof(conf->link_da) / sizeof(*conf->link_da),
+ conf->link_attributes);
+ if (conf->link_da_num < 0) {
+ usage(64);
+ }
+
+ link_tree = rbtree_create((rbcmp) rs_rtx_cmp, _unmark_link, 0);
+ if (!link_tree) {
+ ERROR("Failed creating RTX tree");
+ goto finish;
}
}
- if (radius_filter) {
- parsecode = userparse(NULL, radius_filter, &filter_vps);
- if (parsecode == T_OP_INVALID) {
- fprintf(stderr, "radsniff: Invalid RADIUS filter \"%s\" (%s)\n", radius_filter, fr_strerror());
- exit(64);
+ if (conf->filter_request) {
+ vp_cursor_t cursor;
+ VALUE_PAIR *type;
+
+ if (rs_build_filter(&conf->filter_request_vps, conf->filter_request) < 0) {
+ usage(64);
+ }
+
+ fr_cursor_init(&cursor, &conf->filter_request_vps);
+ type = fr_cursor_next_by_num(&cursor, PW_PACKET_TYPE, 0, TAG_ANY);
+ if (type) {
+ fr_cursor_remove(&cursor);
+ conf->filter_request_code = type->vp_integer;
+ talloc_free(type);
}
+ }
- if (!filter_vps) {
- fprintf(stderr, "radsniff: Empty RADIUS filter \"%s\"\n", radius_filter);
- exit(64);
+ if (conf->filter_response) {
+ vp_cursor_t cursor;
+ VALUE_PAIR *type;
+
+ if (rs_build_filter(&conf->filter_response_vps, conf->filter_response) < 0) {
+ usage(64);
}
- filter_tree = rbtree_create((rbcmp) fr_packet_cmp, _rb_rad_free, 0);
- if (!filter_tree) {
- fprintf(stderr, "radsniff: Failed creating filter tree\n");
- exit(1);
+ fr_cursor_init(&cursor, &conf->filter_response_vps);
+ type = fr_cursor_next_by_num(&cursor, PW_PACKET_TYPE, 0, TAG_ANY);
+ if (type) {
+ fr_cursor_remove(&cursor);
+ conf->filter_response_code = type->vp_integer;
+ talloc_free(type);
}
}
/*
- * Setup the request tree
+ * Default to logging and capturing all events
*/
- request_tree = rbtree_create((rbcmp) fr_packet_cmp, _rb_rad_free, 0);
- if (!request_tree) {
- fprintf(stderr, "radsniff: Failed creating request tree\n");
- exit(1);
+ if (conf->event_flags == 0) {
+ DEBUG("Logging all events");
+ memset(&conf->event_flags, 0xff, sizeof(conf->event_flags));
+ }
+
+ /*
+ * If we need to list attributes, link requests using attributes, filter attributes
+ * or print the packet contents, we need to decode the attributes.
+ *
+ * But, if were just logging requests, or graphing packets, we don't need to decode
+ * attributes.
+ */
+ if (conf->list_da_num || conf->link_da_num || conf->filter_response_vps || conf->filter_request_vps ||
+ conf->print_packet) {
+ conf->decode_attrs = true;
}
/*
- * Allocate a null packet for decrypting attributes in CoA requests
+ * Setup the request tree
*/
- nullpacket = rad_alloc(NULL, 0);
- if (!nullpacket) {
- fprintf(stderr, "radsniff: Out of memory\n");
- exit(1);
+ request_tree = rbtree_create((rbcmp) rs_packet_cmp, _unmark_request, 0);
+ if (!request_tree) {
+ ERROR("Failed creating request tree");
+ goto finish;
}
/*
- * Get the default capture device
+ * Get the default capture device
*/
- if (!from_stdin && !from_file && !from_dev) {
- from_dev = pcap_lookupdev(errbuf);
- if (!from_dev) {
- fprintf(stderr, "radsniff: Failed discovering default interface (%s)\n", errbuf);
- exit(1);
+ if (!conf->from_stdin && !conf->from_file && !conf->from_dev) {
+ pcap_if_t *all_devices; /* List of all devices libpcap can listen on */
+ pcap_if_t *dev_p;
+
+ if (pcap_findalldevs(&all_devices, errbuf) < 0) {
+ ERROR("Error getting available capture devices: %s", errbuf);
+ goto finish;
+ }
+
+ if (!all_devices) {
+ ERROR("No capture files specified and no live interfaces available");
+ ret = 64;
+ goto finish;
}
- INFO(log_dst, "Capturing from interface \"%s\"\n", from_dev);
+ for (dev_p = all_devices;
+ dev_p;
+ dev_p = dev_p->next) {
+ /* Don't use the any devices, it's horribly broken */
+ if (!strcmp(dev_p->name, "any")) continue;
+ *in_head = fr_pcap_init(conf, dev_p->name, PCAP_INTERFACE_IN);
+ in_head = &(*in_head)->next;
+ }
+ conf->from_auto = true;
+ conf->from_dev = true;
+ INFO("Defaulting to capture on all interfaces");
}
/*
- * Print captures values which will be used
+ * Print captures values which will be used
*/
if (fr_debug_flag > 2) {
- DEBUG1(log_dst, "Sniffing with options:\n");
- if (from_dev) DEBUG1(log_dst, " Device : [%s]\n", from_dev);
- if (limit > 0) DEBUG1(log_dst, " Capture limit (packets) : [%d]\n", limit);
- DEBUG1(log_dst, " PCAP filter : [%s]\n", pcap_filter);
- DEBUG1(log_dst, " RADIUS secret : [%s]\n", radius_secret);
- if (filter_vps){DEBUG1(log_dst, " RADIUS filter :\n");
- vp_printlist(log_dst, filter_vps);
+ DEBUG2("Sniffing with options:");
+ if (conf->from_dev) {
+ char *buff = fr_pcap_device_names(conf, in, ' ');
+ DEBUG2(" Device(s) : [%s]", buff);
+ talloc_free(buff);
+ }
+ if (out) {
+ DEBUG2(" Writing to : [%s]", out->name);
+ }
+ if (conf->limit > 0) {
+ DEBUG2(" Capture limit (packets) : [%" PRIu64 "]", conf->limit);
+ }
+ DEBUG2(" PCAP filter : [%s]", conf->pcap_filter);
+ DEBUG2(" RADIUS secret : [%s]", conf->radius_secret);
+
+ if (conf->filter_request_code) {
+ DEBUG2(" RADIUS request code : [%s]", fr_packet_codes[conf->filter_request_code]);
+ }
+
+ if (conf->filter_request_vps){
+ DEBUG2(" RADIUS request filter :");
+ vp_printlist(fr_log_fp, conf->filter_request_vps);
+ }
+
+ if (conf->filter_response_code) {
+ DEBUG2(" RADIUS response code : [%s]", fr_packet_codes[conf->filter_response_code]);
+ }
+
+ if (conf->filter_response_vps){
+ DEBUG2(" RADIUS response filter :");
+ vp_printlist(fr_log_fp, conf->filter_response_vps);
}
}
/*
- * Figure out whether were doing a reading from a file, doing a live
- * capture or reading from stdin.
+ * Setup collectd templates
*/
- if (from_file) {
- in = pcap_open_offline(from_file, errbuf);
-#ifdef HAVE_PCAP_FOPEN_OFFLINE
- } else if (from_stdin) {
- in = pcap_fopen_offline(stdin, errbuf);
-#endif
- } else if (from_dev) {
- pcap_lookupnet(from_dev, &ip_addr, &ip_mask, errbuf);
- in = pcap_open_live(from_dev, 65536, 1, 1, errbuf);
- } else {
- fprintf(stderr, "radsniff: No capture devices available\n");
+#ifdef HAVE_COLLECTDC_H
+ if (conf->stats.out == RS_STATS_OUT_COLLECTD) {
+ size_t i;
+ rs_stats_tmpl_t *tmpl, **next;
+
+ if (rs_stats_collectd_open(conf) < 0) {
+ exit(EXIT_FAILURE);
+ }
+
+ next = &conf->stats.tmpl;
+
+ for (i = 0; i < (sizeof(rs_useful_codes) / sizeof(*rs_useful_codes)); i++) {
+ tmpl = rs_stats_collectd_init_latency(conf, next, conf, "exchanged",
+ &stats.exchange[rs_useful_codes[i]],
+ rs_useful_codes[i]);
+ if (!tmpl) {
+ ERROR("Error allocating memory for stats template");
+ goto finish;
+ }
+ next = &(tmpl->next);
+ }
}
+#endif
- if (!in) {
- fprintf(stderr, "radsniff: Failed opening input (%s)\n", errbuf);
- exit(1);
+ /*
+ * This actually opens the capture interfaces/files (we just allocated the memory earlier)
+ */
+ {
+ fr_pcap_t *tmp;
+ fr_pcap_t **tmp_p = &tmp;
+
+ for (in_p = in;
+ in_p;
+ in_p = in_p->next) {
+ in_p->promiscuous = conf->promiscuous;
+ in_p->buffer_pkts = conf->buffer_pkts;
+ if (fr_pcap_open(in_p) < 0) {
+ ERROR("Failed opening pcap handle (%s): %s", in_p->name, fr_strerror());
+ if (conf->from_auto || (in_p->type == PCAP_FILE_IN)) {
+ continue;
+ }
+
+ goto finish;
+ }
+
+ if (conf->pcap_filter) {
+ if (fr_pcap_apply_filter(in_p, conf->pcap_filter) < 0) {
+ ERROR("Failed applying filter");
+ goto finish;
+ }
+ }
+
+ *tmp_p = in_p;
+ tmp_p = &(in_p->next);
+ }
+ *tmp_p = NULL;
+ in = tmp;
+
+ if (!in) {
+ ERROR("No PCAP sources available");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Clear any irrelevant errors */
+ fr_strerror();
}
- if (to_file) {
- out = pcap_dump_open(in, to_file);
- if (!out) {
- fprintf(stderr, "radsniff: Failed opening output file (%s)\n", pcap_geterr(in));
- exit(1);
+ /*
+ * Open our output interface (if we have one);
+ */
+ if (out) {
+ out->link_type = -1; /* Infer output link type from input */
+
+ for (in_p = in;
+ in_p;
+ in_p = in_p->next) {
+ if (out->link_type < 0) {
+ out->link_type = in_p->link_type;
+ continue;
+ }
+
+ if (out->link_type != in_p->link_type) {
+ ERROR("Asked to write to output file, but inputs do not have the same link type");
+ ret = 64;
+ goto finish;
+ }
}
-#ifdef HAVE_PCAP_DUMP_FOPEN
- } else if (to_stdout) {
- out = pcap_dump_fopen(in, stdout);
- if (!out) {
- fprintf(stderr, "radsniff: Failed opening stdout (%s)\n", pcap_geterr(in));
- exit(1);
+
+ assert(out->link_type > 0);
+
+ if (fr_pcap_open(out) < 0) {
+ ERROR("Failed opening pcap output (%s): %s", out->name, fr_strerror());
+ goto finish;
}
-#endif
}
/*
- * Apply the rules
+ * Setup and enter the main event loop. Who needs libev when you can roll your own...
*/
- if (pcap_compile(in, &fp, pcap_filter, 0, ip_mask) < 0) {
- fprintf(stderr, "radsniff: Failed compiling PCAP filter (%s)\n", pcap_geterr(in));
- exit(1);
+ {
+ struct timeval now;
+ rs_update_t update;
+
+ char *buff;
+
+ memset(&stats, 0, sizeof(stats));
+ memset(&update, 0, sizeof(update));
+
+ events = fr_event_list_create(conf, _rs_event_status);
+ if (!events) {
+ ERROR();
+ goto finish;
+ }
+
+ /*
+ * Initialise the signal handler pipe
+ */
+ if (pipe(self_pipe) < 0) {
+ ERROR("Couldn't open signal pipe: %s", fr_syserror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (!fr_event_fd_insert(events, 0, self_pipe[0], rs_signal_action, events)) {
+ ERROR("Failed inserting signal pipe descriptor: %s", fr_strerror());
+ goto finish;
+ }
+
+ /*
+ * Now add fd's for each of the pcap sessions we opened
+ */
+ for (in_p = in;
+ in_p;
+ in_p = in_p->next) {
+ rs_event_t *event;
+
+ event = talloc_zero(events, rs_event_t);
+ event->list = events;
+ event->in = in_p;
+ event->out = out;
+ event->stats = &stats;
+
+ if (!fr_event_fd_insert(events, 0, in_p->fd, rs_got_packet, event)) {
+ ERROR("Failed inserting file descriptor");
+ goto finish;
+ }
+ }
+
+ buff = fr_pcap_device_names(conf, in, ' ');
+ DEBUG("Sniffing on (%s)", buff);
+ talloc_free(buff);
+
+ gettimeofday(&now, NULL);
+
+ /*
+ * Insert our stats processor
+ */
+ if (conf->stats.interval) {
+ static fr_event_t *event;
+
+ update.list = events;
+ update.stats = &stats;
+ update.in = in;
+
+ now.tv_sec += conf->stats.interval;
+ now.tv_usec = 0;
+ if (!fr_event_insert(events, rs_stats_process, (void *) &update, &now, &event)) {
+ ERROR("Failed inserting stats event");
+ }
+
+ INFO("Muting stats for the next %i milliseconds (warmup)", conf->stats.timeout);
+ rs_tv_add_ms(&now, conf->stats.timeout, &stats.quiet);
+ }
}
- if (pcap_setfilter(in, &fp) < 0) {
- fprintf(stderr, "radsniff: Failed applying PCAP filter (%s)\n", pcap_geterr(in));
- exit(1);
+
+ /*
+ * Do this as late as possible so we can return an error code if something went wrong.
+ */
+ if (conf->daemonize) {
+ rs_daemonize(conf->pidfile);
}
/*
- * Enter the main capture loop...
+ * Setup signal handlers so we always exit gracefully, ensuring output buffers are always
+ * flushed.
*/
- pcap_loop(in, limit, got_packet, NULL);
+ fr_set_signal(SIGPIPE, rs_signal_self);
+ fr_set_signal(SIGINT, rs_signal_self);
+ fr_set_signal(SIGTERM, rs_signal_self);
+#ifdef SIGQUIT
+ fr_set_signal(SIGQUIT, rs_signal_self);
+#endif
+
+ fr_event_loop(events); /* Enter the main event loop */
+
+ DEBUG("Done sniffing");
+
+ finish:
+
+ cleanup = true;
/*
- * ...were done capturing.
+ * Free all the things! This also closes all the sockets and file descriptors
*/
- pcap_close(in);
- if (out) {
- pcap_dump_close(out);
- }
+ talloc_free(conf);
- if (filter_tree) {
- rbtree_free(filter_tree);
+ if (conf->daemonize) {
+ unlink(conf->pidfile);
}
- INFO(log_dst, "Done sniffing\n");
-
- return 0;
+ return ret;
}
TARGET :=
endif
-SOURCES := radsniff.c
+SOURCES := radsniff.c collectd.c
TGT_PREREQS := libfreeradius-radius.a
-TGT_LDLIBS := $(LIBS) $(PCAP_LIBS)
+TGT_LDLIBS := $(LIBS) $(PCAP_LIBS) $(COLLECTDC_LIBS)
+TGT_LDFLAGS := $(LDFLAGS) $(PCAP_LDFLAGS) $(COLLECTDC_LDFLAGS)
;;
-d)
OPTIONS="$OPTIONS -d $2"
- shift;shift
+ shift;shift
;;
-P)
OPTIONS="$OPTIONS -P $2"
- shift;shift
+ shift;shift
;;
-x)
OPTIONS="$OPTIONS -x"
shift
;;
- *)
+ *)
usage
;;
esac
/*
* Global, for log.c to use.
*/
-struct main_config_t mainconfig;
+struct main_config_t main_config;
#include <sys/wait.h>
pid_t rad_fork(void)
#endif
struct radutmp_config_t {
- char *radutmp_fn;
+ char const *radutmp_fn;
} radutmpconfig;
static const CONF_PARSER module_config[] = {
- { "filename", PW_TYPE_FILE_INPUT, 0, &radutmpconfig.radutmp_fn, RADUTMP },
+ { "filename", FR_CONF_POINTER(PW_TYPE_FILE_INPUT, &radutmpconfig.radutmp_fn), RADUTMP },
{ NULL, -1, 0, NULL, NULL }
};
raddb_dir = RADIUS_DIR;
+#ifndef NDEBUG
+ if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
+ fr_perror("radwho");
+ exit(EXIT_FAILURE);
+ }
+#endif
+
talloc_set_log_stderr();
while((c = getopt(argc, argv, "d:fF:nN:sSipP:crRu:U:Z")) != EOF) switch(c) {
}
/*
+ * Mismatch between the binary and the libraries it depends on
+ */
+ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
+ fr_perror("radwho");
+ return 1;
+ }
+
+ /*
* Be safe.
*/
if (zap && !radiusoutput) zap = 0;
if (radutmp_file) goto have_radutmp;
/*
- * Initialize mainconfig
+ * Initialize main_config
*/
- memset(&mainconfig, 0, sizeof(mainconfig));
+ memset(&main_config, 0, sizeof(main_config));
/* Read radiusd.conf */
snprintf(buffer, sizeof(buffer), "%.200s/radiusd.conf", raddb_dir);
*/
if ((fp = fopen(radutmp_file, "r")) == NULL) {
fprintf(stderr, "%s: Error reading %s: %s\n",
- progname, radutmp_file, strerror(errno));
+ progname, radutmp_file, fr_syserror(errno));
return 0;
}
usage() {
echo "Usage: radzap [options] server[:port] secret" >&2
- echo " -h Print usage help information."
- echo " -d raddb_directory: directory where radiusd.conf is located."
- echo " -N nas_ip_address: IP address of the NAS to zap."
+ echo " -h Print usage help information."
+ echo " -d raddb_directory: directory where radiusd.conf is located."
+ echo " -N nas_ip_address: IP address of the NAS to zap."
echo " -P nas_port: NAS port that the user is logged into."
echo " -u username: Name of user to zap (case insensitive)."
echo " -U username: like -u, but case-sensitive."
typedef struct realm_config_t {
CONF_SECTION *cs;
- int dead_time;
- int retry_count;
- int retry_delay;
+ uint32_t dead_time;
+ uint32_t retry_count;
+ uint32_t retry_delay;
bool fallback;
bool wake_all_if_all_dead;
} realm_config_t;
* Map the proxy server configuration parameters to variables.
*/
static const CONF_PARSER proxy_config[] = {
- { "retry_delay", PW_TYPE_INTEGER,
- offsetof(realm_config_t, retry_delay),
- NULL, STRINGIFY(RETRY_DELAY) },
+ { "retry_delay", FR_CONF_OFFSET(PW_TYPE_INTEGER, realm_config_t, retry_delay), STRINGIFY(RETRY_DELAY) },
- { "retry_count", PW_TYPE_INTEGER,
- offsetof(realm_config_t, retry_count),
- NULL, STRINGIFY(RETRY_COUNT) },
+ { "retry_count", FR_CONF_OFFSET(PW_TYPE_INTEGER, realm_config_t, retry_count), STRINGIFY(RETRY_COUNT) },
- { "default_fallback", PW_TYPE_BOOLEAN,
- offsetof(realm_config_t, fallback),
- NULL, "no" },
+ { "default_fallback", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, realm_config_t, fallback), "no" },
- { "dead_time", PW_TYPE_INTEGER,
- offsetof(realm_config_t, dead_time),
- NULL, STRINGIFY(DEAD_TIME) },
+ { "dead_time", FR_CONF_OFFSET(PW_TYPE_INTEGER, realm_config_t, dead_time), STRINGIFY(DEAD_TIME) },
- { "wake_all_if_all_dead", PW_TYPE_BOOLEAN,
- offsetof(realm_config_t, wake_all_if_all_dead),
- NULL, "no" },
+ { "wake_all_if_all_dead", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, realm_config_t, wake_all_if_all_dead), "no" },
{ NULL, -1, 0, NULL, NULL }
};
#ifdef WITH_PROXY
static void home_server_free(void *data)
{
- home_server *home = data;
+ home_server_t *home = data;
talloc_free(home);
}
static int home_server_name_cmp(void const *one, void const *two)
{
- home_server const *a = one;
- home_server const *b = two;
+ home_server_t const *a = one;
+ home_server_t const *b = two;
if (a->type < b->type) return -1;
if (a->type > b->type) return +1;
static int home_server_addr_cmp(void const *one, void const *two)
{
int rcode;
- home_server const *a = one;
- home_server const *b = two;
+ home_server_t const *a = one;
+ home_server_t const *b = two;
if (a->server && !b->server) return -1;
if (!a->server && b->server) return +1;
#ifdef WITH_STATS
static int home_server_number_cmp(void const *one, void const *two)
{
- home_server const *a = one;
- home_server const *b = two;
+ home_server_t const *a = one;
+ home_server_t const *b = two;
return (a->number - b->number);
}
}
-static size_t xlat_cs(CONF_SECTION *cs, char const *fmt, char *out, size_t outlen)
-
+static size_t CC_HINT(nonnull) xlat_cs(CONF_SECTION *cs, char const *fmt, char *out, size_t outlen)
{
char const *value = NULL;
/*
* Xlat for %{home_server:foo}
*/
-static ssize_t xlat_home_server(UNUSED void *instance, REQUEST *request,
- char const *fmt, char *out, size_t outlen)
+static ssize_t CC_HINT(nonnull) xlat_home_server(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
{
- if (!fmt || !out || (outlen < 1)) return 0;
-
- if (!request || !request->home_server) {
+ if (!request->home_server) {
RWDEBUG("No home_server associated with this request");
*out = '\0';
/*
* Xlat for %{home_server_pool:foo}
*/
-static ssize_t xlat_server_pool(UNUSED void *instance, REQUEST *request,
- char const *fmt, char *out, size_t outlen)
+static ssize_t CC_HINT(nonnull) xlat_server_pool(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
{
- if (!fmt || !out || (outlen < 1)) return 0;
-
- if (!request || !request->home_pool) {
+ if (!request->home_pool) {
RWDEBUG("No home_pool associated with this request");
*out = '\0';
#ifdef WITH_PROXY
static CONF_PARSER limit_config[] = {
- { "max_connections", PW_TYPE_INTEGER,
- offsetof(home_server, limit.max_connections), NULL, "16" },
-
- { "max_requests", PW_TYPE_INTEGER,
- offsetof(home_server, limit.max_requests), NULL, "0" },
-
- { "lifetime", PW_TYPE_INTEGER,
- offsetof(home_server, limit.lifetime), NULL, "0" },
-
- { "idle_timeout", PW_TYPE_INTEGER,
- offsetof(home_server, limit.idle_timeout), NULL, "0" },
+ { "max_connections", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, limit.max_connections), "16" },
+ { "max_requests", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, limit.max_requests), "0" },
+ { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, limit.lifetime), "0" },
+ { "idle_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, limit.idle_timeout), "0" },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
-static struct in_addr hs_ip4addr;
-static struct in6_addr hs_ip6addr;
-static char *hs_srcipaddr = NULL;
-static char *hs_type = NULL;
-static char *hs_check = NULL;
-static char *hs_virtual_server = NULL;
+static fr_ipaddr_t hs_ipaddr;
+static char const *hs_srcipaddr = NULL;
+static char const *hs_type = NULL;
+static char const *hs_check = NULL;
+static char const *hs_virtual_server = NULL;
#ifdef WITH_TCP
-static char *hs_proto = NULL;
+static char const *hs_proto = NULL;
#endif
#ifdef WITH_COA
static CONF_PARSER home_server_coa[] = {
- { "irt", PW_TYPE_INTEGER,
- offsetof(home_server, coa_irt), 0, STRINGIFY(2) },
- { "mrt", PW_TYPE_INTEGER,
- offsetof(home_server, coa_mrt), 0, STRINGIFY(16) },
- { "mrc", PW_TYPE_INTEGER,
- offsetof(home_server, coa_mrc), 0, STRINGIFY(5) },
- { "mrd", PW_TYPE_INTEGER,
- offsetof(home_server, coa_mrd), 0, STRINGIFY(30) },
+ { "irt", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, coa_irt), STRINGIFY(2) },
+ { "mrt", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, coa_mrt), STRINGIFY(16) },
+ { "mrc", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, coa_mrc), STRINGIFY(5) },
+ { "mrd", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, coa_mrd), STRINGIFY(30) },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
#endif
static CONF_PARSER home_server_config[] = {
- { "ipaddr", PW_TYPE_IPADDR,
- 0, &hs_ip4addr, NULL },
- { "ipv6addr", PW_TYPE_IPV6ADDR,
- 0, &hs_ip6addr, NULL },
- { "virtual_server", PW_TYPE_STRING_PTR,
- 0, &hs_virtual_server, NULL },
+ { "ipaddr", FR_CONF_POINTER(PW_TYPE_IP_ADDR, &hs_ipaddr), NULL },
+ { "ipv4addr", FR_CONF_POINTER(PW_TYPE_IPV4_ADDR, &hs_ipaddr), NULL },
+ { "ipv6addr", FR_CONF_POINTER(PW_TYPE_IPV6_ADDR, &hs_ipaddr), NULL },
+ { "virtual_server", FR_CONF_POINTER(PW_TYPE_STRING, &hs_virtual_server), NULL },
- { "port", PW_TYPE_INTEGER,
- offsetof(home_server,port), NULL, "0" },
+ { "port", FR_CONF_OFFSET(PW_TYPE_SHORT, home_server_t, port), "0" },
- { "type", PW_TYPE_STRING_PTR,
- 0, &hs_type, NULL },
+ { "type", FR_CONF_POINTER(PW_TYPE_STRING, &hs_type), NULL },
#ifdef WITH_TCP
- { "proto", PW_TYPE_STRING_PTR,
- 0, &hs_proto, NULL },
+ { "proto", FR_CONF_POINTER(PW_TYPE_STRING, &hs_proto), NULL },
#endif
- { "secret", PW_TYPE_STRING_PTR,
- offsetof(home_server,secret), NULL, NULL},
-
- { "src_ipaddr", PW_TYPE_STRING_PTR,
- 0, &hs_srcipaddr, NULL },
-
- { "response_window", PW_TYPE_INTEGER,
- offsetof(home_server,response_window), NULL, "30" },
- { "max_outstanding", PW_TYPE_INTEGER,
- offsetof(home_server,max_outstanding), NULL, "65536" },
-
- { "zombie_period", PW_TYPE_INTEGER,
- offsetof(home_server,zombie_period), NULL, "40" },
- { "status_check", PW_TYPE_STRING_PTR,
- 0, &hs_check, "none" },
- { "ping_check", PW_TYPE_STRING_PTR,
- 0, &hs_check, NULL },
-
- { "ping_interval", PW_TYPE_INTEGER,
- offsetof(home_server,ping_interval), NULL, "30" },
- { "check_interval", PW_TYPE_INTEGER,
- offsetof(home_server,ping_interval), NULL, "30" },
- { "num_answers_to_alive", PW_TYPE_INTEGER,
- offsetof(home_server,num_pings_to_alive), NULL, "3" },
- { "revive_interval", PW_TYPE_INTEGER,
- offsetof(home_server,revive_interval), NULL, "300" },
- { "status_check_timeout", PW_TYPE_INTEGER,
- offsetof(home_server,ping_timeout), NULL, "4" },
-
- { "username", PW_TYPE_STRING_PTR,
- offsetof(home_server,ping_user_name), NULL, NULL},
- { "password", PW_TYPE_STRING_PTR,
- offsetof(home_server,ping_user_password), NULL, NULL},
+ { "secret", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, home_server_t, secret), NULL },
+
+ { "src_ipaddr", FR_CONF_POINTER(PW_TYPE_STRING, &hs_srcipaddr), NULL },
+
+ { "response_window", FR_CONF_OFFSET(PW_TYPE_TIMEVAL, home_server_t, response_window), "30" },
+ { "max_outstanding", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, max_outstanding), "65536" },
+
+ { "zombie_period", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, zombie_period), "40" },
+ { "status_check", FR_CONF_POINTER(PW_TYPE_STRING, &hs_check), "none" },
+ { "ping_check", FR_CONF_POINTER(PW_TYPE_STRING, &hs_check), NULL },
+
+ { "ping_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, ping_interval), "30" },
+ { "check_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, ping_interval), "30" },
+ { "num_answers_to_alive", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, num_pings_to_alive), "3" },
+ { "revive_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, revive_interval), "300" },
+ { "status_check_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, ping_timeout), "4" },
+
+ { "username", FR_CONF_OFFSET(PW_TYPE_STRING, home_server_t, ping_user_name), NULL },
+ { "password", FR_CONF_OFFSET(PW_TYPE_STRING, home_server_t, ping_user_password), NULL },
#ifdef WITH_STATS
- { "historic_average_window", PW_TYPE_INTEGER,
- offsetof(home_server,ema.window), NULL, NULL },
+ { "historic_average_window", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, ema.window), NULL },
#endif
#ifdef WITH_COA
- { "coa", PW_TYPE_SUBSECTION, 0, NULL, (void const *) home_server_coa },
+ { "coa", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) home_server_coa },
#endif
- { "limit", PW_TYPE_SUBSECTION, 0, NULL, (void const *) limit_config },
+ { "limit", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) limit_config },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
}
-int realms_home_server_add(home_server *home, CONF_SECTION *cs, int dual)
+int realms_home_server_add(home_server_t *home, CONF_SECTION *cs, int dual)
{
CONF_SECTION *parent = NULL;
const char * name2 = home->name;
}
#endif
- if (home->max_outstanding < 8) home->max_outstanding = 8;
- if (home->max_outstanding > 65536*16) home->max_outstanding = 65536*16;
-
- if (home->ping_interval < 6) home->ping_interval = 6;
- if (home->ping_interval > 120) home->ping_interval = 120;
+ FR_INTEGER_BOUND_CHECK("max_outstanding", home->max_outstanding, >=, 8);
+ FR_INTEGER_BOUND_CHECK("max_outstanding", home->max_outstanding, <=, 65536*16);
- if (home->response_window < 1) home->response_window = 1;
- if (home->response_window > 60) home->response_window = 60;
- if (home->response_window > mainconfig.max_request_time) home->response_window = mainconfig.max_request_time;
+ FR_INTEGER_BOUND_CHECK("ping_interval", home->ping_interval, >=, 6);
+ FR_INTEGER_BOUND_CHECK("ping_interval", home->ping_interval, <=, 120);
- if (home->zombie_period < 1) home->zombie_period = 1;
- if (home->zombie_period > 120) home->zombie_period = 120;
+ FR_TIMEVAL_BOUND_CHECK("response_window", &home->response_window, >=, 0, 1000);
+ FR_TIMEVAL_BOUND_CHECK("response_window", &home->response_window, <=, 60, 0);
+ FR_TIMEVAL_BOUND_CHECK("response_window", &home->response_window, <=,
+ main_config.max_request_time, 0);
- if (home->zombie_period < home->response_window) {
- home->zombie_period = home->response_window;
+ /*
+ * Track the minimum response window, so that we can
+ * correctly set the timers in process.c
+ */
+ if (timercmp(&main_config.init_delay, &home->response_window, >)) {
+ main_config.init_delay = home->response_window;
}
- if (home->num_pings_to_alive < 3) home->num_pings_to_alive = 3;
- if (home->num_pings_to_alive > 10) home->num_pings_to_alive = 10;
+ FR_INTEGER_BOUND_CHECK("zombie_period", home->zombie_period, >=, 1);
+ FR_INTEGER_BOUND_CHECK("zombie_period", home->zombie_period, <=, 120);
+ FR_INTEGER_BOUND_CHECK("zombie_period", home->zombie_period, >=, (uint32_t) home->response_window.tv_sec);
+
+ FR_INTEGER_BOUND_CHECK("num_pings_to_alive", home->num_pings_to_alive, >=, 3);
+ FR_INTEGER_BOUND_CHECK("num_pings_to_alive", home->num_pings_to_alive, <=, 10);
- if (home->ping_timeout < 3) home->ping_timeout = 3;
- if (home->ping_timeout > 10) home->ping_timeout = 10;
+ FR_INTEGER_BOUND_CHECK("ping_timeout", home->ping_timeout, >=, 3);
+ FR_INTEGER_BOUND_CHECK("ping_timeout", home->ping_timeout, <=, 10);
- if (home->revive_interval < 60) home->revive_interval = 60;
- if (home->revive_interval > 3600) home->revive_interval = 3600;
+ FR_INTEGER_BOUND_CHECK("revive_interval", home->revive_interval, >=, 60);
+ FR_INTEGER_BOUND_CHECK("revive_interval", home->revive_interval, <=, 3600);
#ifdef WITH_COA
- if (home->coa_irt < 1) home->coa_irt = 1;
- if (home->coa_irt > 5) home->coa_irt = 5;
+ FR_INTEGER_BOUND_CHECK("coa_irt", home->coa_irt, >=, 1);
+ FR_INTEGER_BOUND_CHECK("coa_irt", home->coa_irt, <=, 5);
- if (home->coa_mrc < 0) home->coa_mrc = 0;
- if (home->coa_mrc > 20 ) home->coa_mrc = 20;
+ FR_INTEGER_BOUND_CHECK("coa_mrc", home->coa_mrc, <=, 20);
- if (home->coa_mrt < 0) home->coa_mrt = 0;
- if (home->coa_mrt > 30 ) home->coa_mrt = 30;
+ FR_INTEGER_BOUND_CHECK("coa_mrt", home->coa_mrt, <=, 30);
- if (home->coa_mrd < 5) home->coa_mrd = 5;
- if (home->coa_mrd > 60 ) home->coa_mrd = 60;
+ FR_INTEGER_BOUND_CHECK("coa_mrd", home->coa_mrd, >=, 5);
+ FR_INTEGER_BOUND_CHECK("coa_mrd", home->coa_mrd, <=, 60);
#endif
- if (home->limit.max_connections > 1024) home->limit.max_connections = 1024;
+ FR_INTEGER_BOUND_CHECK("max_connections", home->limit.max_connections, <=, 1024);
#ifdef WITH_TCP
/*
home->limit.idle_timeout = 0;
parent = cf_item_parent(cf_sectiontoitem(cs));
- if (parent && strcmp(cf_section_name1(parent), "server") == 0) {
+ if (strcmp(cf_section_name1(parent), "server") == 0) {
home->parent_server = cf_section_name2(parent);
}
if (dual) {
- home_server *home2 = rad_malloc(sizeof(*home2));
+ home_server_t *home2 = talloc(home, home_server_t);
memcpy(home2, home, sizeof(*home2));
free(home2);
return 0;
}
-
+
if (!home->server &&
!rbtree_insert(home_servers_byaddr, home2)) {
rbtree_deletebydata(home_servers_byname, home2);
static int home_server_add(realm_config_t *rc, CONF_SECTION *cs)
{
char const *name2;
- home_server *home;
- int dual = false;
+ home_server_t *home;
+ bool dual = false;
CONF_PAIR *cp;
CONF_SECTION *tls;
name2 = cf_section_name2(cs);
if (!name2) {
- cf_log_err_cs(cs,
- "Home server section is missing a name.");
+ cf_log_err_cs(cs, "Home server section is missing a name");
return 0;
}
- home = talloc_zero(rc, home_server);
+ home = talloc_zero(rc, home_server_t);
home->name = name2;
home->cs = cs;
* Last packet sent / received are zero.
*/
- memset(&hs_ip4addr, 0, sizeof(hs_ip4addr));
- memset(&hs_ip6addr, 0, sizeof(hs_ip6addr));
+ memset(&hs_ipaddr, 0, sizeof(hs_ipaddr));
if (cf_section_parse(cs, home, home_server_config) < 0) {
goto error;
}
/*
* Figure out which one to use.
*/
- if (cf_pair_find(cs, "ipaddr")) {
- home->ipaddr.af = AF_INET;
- home->ipaddr.ipaddr.ip4addr = hs_ip4addr;
-
- } else if (cf_pair_find(cs, "ipv6addr")) {
- home->ipaddr.af = AF_INET6;
- home->ipaddr.ipaddr.ip6addr = hs_ip6addr;
-
+ if (cf_pair_find(cs, "ipaddr") || cf_pair_find(cs, "ipv4addr") || cf_pair_find(cs, "ipv6addr")) {
+ if (is_wildcard(&hs_ipaddr)) {
+ cf_log_err_cs(cs, "Wildcard '*' addresses are not permitted for home servers");
+ goto error;
+ }
+ home->ipaddr = hs_ipaddr;
} else if ((cp = cf_pair_find(cs, "virtual_server")) != NULL) {
home->ipaddr.af = AF_UNSPEC;
home->server = cf_pair_value(cp);
goto skip_port;
} else {
- cf_log_err_cs(cs,
- "No ipaddr, ipv6addr, or virtual_server defined for home server \"%s\".",
- name2);
+ cf_log_err_cs(cs, "No ipaddr, ipv4addr, ipv6addr, or virtual_server defined for home server \"%s\"", name2);
error:
- talloc_free(hs_type);
hs_type = NULL;
hs_check = NULL;
hs_srcipaddr = NULL;
return 0;
}
- if (!home->port || (home->port > 65535)) {
- cf_log_err_cs(cs,
- "No port, or invalid port defined for home server %s.",
- name2);
- goto error;
- }
-
- if (0) {
- cf_log_err_cs(cs,
- "Fatal error! Home server %s is ourselves!",
- name2);
- goto error;
- }
-
- if (!home->secret) {
- cf_log_err_cs(cs,
- "No shared secret defined for home server %s.",
- name2);
+ if (home->port == 0) {
+ cf_log_err_cs(cs, "No port, or invalid port defined for home server %s", name2);
goto error;
}
* Use a reasonable default.
*/
skip_port:
- if (!hs_type) hs_type = talloc_strdup(cs, "auth+acct");
-
- if (strcasecmp(hs_type, "auth") == 0) {
+ if (!hs_type || (strcasecmp(hs_type, "auth+acct") == 0)) {
+ home->type = HOME_TYPE_AUTH;
+ dual = true;
+ } else if (strcasecmp(hs_type, "auth") == 0) {
home->type = HOME_TYPE_AUTH;
} else if (strcasecmp(hs_type, "acct") == 0) {
home->type = HOME_TYPE_ACCT;
-
- } else if (strcasecmp(hs_type, "auth+acct") == 0) {
- home->type = HOME_TYPE_AUTH;
- dual = true;
-
#ifdef WITH_COA
} else if (strcasecmp(hs_type, "coa") == 0) {
home->type = HOME_TYPE_COA;
dual = false;
if (home->server != NULL) {
- cf_log_err_cs(cs,
- "Home servers of type \"coa\" cannot point to a virtual server");
+ cf_log_err_cs(cs, "Home servers of type \"coa\" cannot point to a virtual server");
goto error;
}
#endif
} else {
- cf_log_err_cs(cs,
- "Invalid type \"%s\" for home server %s.",
- hs_type, name2);
+ cf_log_err_cs(cs, "Invalid type \"%s\" for home server %s.", hs_type, name2);
goto error;
}
- if (hs_type) talloc_free(hs_type);
hs_type = NULL;
if (!hs_check || (strcasecmp(hs_check, "none") == 0)) {
} else {
cf_log_err_cs(cs,
- "Invalid status__check \"%s\" for home server %s.",
+ "Invalid status_check \"%s\" for home server %s.",
hs_check, name2);
goto error;
}
tls = cf_section_sub_find(cs, "tls");
/*
+ * If were doing RADSEC (tls+tcp) the secret should default
+ * to radsec, else a secret must be set.
+ */
+ if (!home->secret) {
+#ifdef WITH_TLS
+ if (tls && (home->proto == IPPROTO_TCP)) {
+ home->secret = "radsec";
+ } else
+#endif
+ {
+ cf_log_err_cs(cs, "No shared secret defined for home server %s", name2);
+ goto error;
+ }
+ }
+
+ /*
* If the home is a virtual server, don't look up source IP.
*/
if (!home->server) {
* address family as the destination IP.
*/
if (hs_srcipaddr) {
- if (ip_hton(hs_srcipaddr, home->ipaddr.af, &home->src_ipaddr) < 0) {
+ if (ip_hton(&home->src_ipaddr, home->ipaddr.af, hs_srcipaddr, false) < 0) {
cf_log_err_cs(cs, "Failed parsing src_ipaddr");
goto error;
}
}
if (tls && (home->proto != IPPROTO_TCP)) {
- cf_log_err_cs(cs, "TLS transport is not available for UDP sockets.");
+ cf_log_err_cs(cs, "TLS transport is not available for UDP sockets");
goto error;
}
#ifndef WITH_TLS
if (tls) {
- cf_log_err_cs(cs, "TLS transport is not available in this executable.");
+ cf_log_err_cs(cs, "TLS transport is not available in this executable");
goto error;
}
#else
*/
static int pool_check_home_server(UNUSED realm_config_t *rc, CONF_PAIR *cp,
char const *name, int server_type,
- home_server **phome)
+ home_server_t **phome)
{
- home_server myhome, *home;
+ home_server_t myhome, *home;
if (!name) {
cf_log_err_cp(cp,
- "No value given for home_server.");
+ "No value given for home_server");
return 0;
}
char const *value;
CONF_PAIR *cp;
int num_home_servers;
- home_server *home;
+ home_server_t *home;
name2 = cf_section_name1(cs);
if (!name2 || ((strcasecmp(name2, "server_pool") != 0) &&
(strcasecmp(name2, "home_server_pool") != 0))) {
cf_log_err_cs(cs,
- "Section is not a home_server_pool.");
+ "Section is not a home_server_pool");
return 0;
}
name2 = cf_section_name2(cs);
if (!name2) {
cf_log_err_cs(cs,
- "Server pool section is missing a name.");
+ "Server pool section is missing a name");
return 0;
}
if (cp) {
#ifdef WITH_COA
if (server_type == HOME_TYPE_COA) {
- cf_log_err_cs(cs, "Home server pools of type \"coa\" cannot have a fallback virtual server.");
+ cf_log_err_cs(cs, "Home server pools of type \"coa\" cannot have a fallback virtual server");
goto error;
}
#endif
value = cf_pair_value(cp);
if (!value) {
cf_log_err_cp(cp,
- "No value given for type.");
+ "No value given for type");
goto error;
}
for (cp = cf_pair_find(cs, "home_server");
cp != NULL;
cp = cf_pair_find_next(cs, cp, "home_server")) {
- home_server myhome;
+ home_server_t myhome;
value = cf_pair_value(cp);
}
if (0) {
- WDEBUG2("Duplicate home server %s in server pool %s", home->name, pool->name);
+ WARN("Duplicate home server %s in server pool %s", home->name, pool->name);
continue;
}
{
#ifdef WITH_PROXY
int i, insert_point, num_home_servers;
- home_server myhome, *home;
+ home_server_t myhome, *home;
home_pool_t mypool, *pool;
CONF_SECTION *subcs;
#else
char const *p;
char *q;
- home = rad_malloc(sizeof(*home));
- memset(home, 0, sizeof(*home));
-
+ home = talloc_zero(rc, home_server_t);
home->name = name;
home->hostname = name;
home->type = type;
q = NULL;
} else if (p == name) {
- cf_log_err_cs(cs,
- "Invalid hostname %s.",
- name);
- free(home);
- return 0;
-
+ cf_log_err_cs(cs, "Invalid hostname %s", name);
+ talloc_free(home);
+ return 0;
} else {
- home->port = atoi(p + 1);
- if ((home->port == 0) || (home->port > 65535)) {
- cf_log_err_cs(cs,
- "Invalid port %s.",
- p + 1);
- free(home);
+ unsigned long port = strtoul(p + 1, NULL, 0);
+ if ((port == 0) || (port > 65535)) {
+ cf_log_err_cs(cs, "Invalid port %s", p + 1);
+ talloc_free(home);
return 0;
}
- q = rad_malloc((p - name) + 1);
+ home->port = (uint16_t)port;
+ q = talloc_array(home, char, (p - name) + 1);
memcpy(q, name, (p - name));
q[p - name] = '\0';
p = q;
}
if (!server) {
- if (ip_hton(p, AF_UNSPEC, &home->ipaddr) < 0) {
+ if (ip_hton(&home->ipaddr, AF_UNSPEC, p, false) < 0) {
cf_log_err_cs(cs,
"Failed looking up hostname %s.",
p);
- free(home);
- free(q);
+ talloc_free(home);
+ talloc_free(q);
return 0;
}
home->src_ipaddr.af = home->ipaddr.af;
home->ipaddr.af = AF_UNSPEC;
home->server = server;
}
- free(q);
+ talloc_free(q);
/*
* Use the old-style configuration.
*/
home->max_outstanding = 65535*16;
home->zombie_period = rc->retry_delay * rc->retry_count;
- if (home->zombie_period == 0) home->zombie_period =30;
- home->response_window = home->zombie_period - 1;
+ if (home->zombie_period < 2) home->zombie_period = 30;
+ home->response_window.tv_sec = home->zombie_period - 1;
+ home->response_window.tv_usec = 0;
home->ping_check = HOME_PING_CHECK_NONE;
if (rbtree_finddata(home_servers_byaddr, home)) {
cf_log_err_cs(cs, "Home server %s has the same IP address and/or port as another home server.", name);
- free(home);
+ talloc_free(home);
return 0;
}
if (!rbtree_insert(home_servers_byname, home)) {
cf_log_err_cs(cs, "Internal error %d adding home server %s.", __LINE__, name);
- free(home);
+ talloc_free(home);
return 0;
}
if (!rbtree_insert(home_servers_byaddr, home)) {
rbtree_deletebydata(home_servers_byname, home);
cf_log_err_cs(cs, "Internal error %d adding home server %s.", __LINE__, name);
- free(home);
+ talloc_free(home);
return 0;
}
cf_log_err_cs(cs,
"Internal error %d adding home server %s.",
__LINE__, name);
- free(home);
+ talloc_free(home);
return 0;
}
#endif
if (num_home_servers == 0) {
cf_log_err_cs(cs, "Internal error counting pools for home server %s.", name);
- free(home);
+ talloc_free(home);
return 0;
}
pool = server_pool_alloc(realm, ldflag, type, num_home_servers);
+ if (!pool) {
+ cf_log_err_cs(cs, "Out of memory");
+ return 0;
+ }
+
pool->cs = cs;
pool->servers[0] = home;
name2 = cf_section_name1(cs);
if (!name2 || (strcasecmp(name2, "realm") != 0)) {
- cf_log_err_cs(cs, "Section is not a realm.");
+ cf_log_err_cs(cs, "Section is not a realm");
return 0;
}
name2 = cf_section_name2(cs);
if (!name2) {
- cf_log_err_cs(cs, "Realm section is missing the realm name.");
+ cf_log_err_cs(cs, "Realm section is missing the realm name");
return 0;
}
if (cp) auth_pool_name = cf_pair_value(cp);
if (cp && auth_pool_name) {
if (auth_pool) {
- cf_log_err_cs(cs, "Cannot use \"pool\" and \"auth_pool\" at the same time.");
+ cf_log_err_cs(cs, "Cannot use \"pool\" and \"auth_pool\" at the same time");
return 0;
}
if (!add_pool_to_realm(rc, cs,
cp = cf_pair_find(cs, "acct_pool");
if (cp) acct_pool_name = cf_pair_value(cp);
if (cp && acct_pool_name) {
- int do_print = true;
+ bool do_print = true;
if (acct_pool) {
- cf_log_err_cs(cs, "Cannot use \"pool\" and \"acct_pool\" at the same time.");
+ cf_log_err_cs(cs, "Cannot use \"pool\" and \"acct_pool\" at the same time");
return 0;
}
cp = cf_pair_find(cs, "coa_pool");
if (cp) coa_pool_name = cf_pair_value(cp);
if (cp && coa_pool_name) {
- int do_print = true;
+ bool do_print = true;
if (!add_pool_to_realm(rc, cs,
coa_pool_name, &coa_pool,
((cp = cf_pair_find(cs, "accthost")) != NULL) ||
((cp = cf_pair_find(cs, "secret")) != NULL) ||
((cp = cf_pair_find(cs, "ldflag")) != NULL)) {
- WDEBUG2("Ignoring old-style configuration entry \"%s\" in realm \"%s\"", cf_pair_attr(cp), r->name);
+ WARN("Ignoring old-style configuration entry \"%s\" in realm \"%s\"", cf_pair_attr(cp), r->name);
}
if (cs) {
if (cf_section_parse(cs, rc, proxy_config) < 0) {
ERROR("Failed parsing proxy section");
-
- talloc_free(rc);
- realms_free();
- return 0;
+ goto error;
}
} else {
rc->dead_time = DEAD_TIME;
for (cs = cf_subsection_find_next(config, NULL, "home_server");
cs != NULL;
cs = cf_subsection_find_next(config, cs, "home_server")) {
- if (!home_server_add(rc, cs)) {
- talloc_free(rc);
- realms_free();
- return 0;
- }
+ if (!home_server_add(rc, cs)) goto error;
}
/*
for (cs = cf_subsection_find_next(server_cs, NULL, "home_server");
cs != NULL;
cs = cf_subsection_find_next(server_cs, cs, "home_server")) {
- if (!home_server_add(rc, cs)) {
- talloc_free(rc);
- realms_free();
- return 0;
- }
+ if (!home_server_add(rc, cs)) goto error;
}
}
#endif
cs != NULL;
cs = cf_subsection_find_next(config, cs, "realm")) {
if (!realm_add(rc, cs)) {
- talloc_free(rc);
+#if defined (WITH_PROXY) || defined (WITH_COA)
+ error:
+#endif
realms_free();
+ /*
+ * Must be called after realms_free as home_servers
+ * parented by rc are in trees freed by realms_free()
+ */
+ talloc_free(rc);
return 0;
}
}
if (cf_data_find(cs, "home_server_pool")) continue;
type = pool_peek_type(config, cs);
- if (type == HOME_TYPE_INVALID) {
- talloc_free(rc);
- realms_free();
- return 0;
- }
-
- if (!server_pool_add(rc, cs, type, true)) {
- talloc_free(rc);
- realms_free();
- return 0;
- }
+ if (type == HOME_TYPE_INVALID) goto error;
+ if (!server_pool_add(rc, cs, type, true)) goto error;
}
#endif
*/
old_rc = realm_config;
realm_config = rc;
- free(old_rc);
+ talloc_free(old_rc);
return 1;
}
* VPs into it. Setup src/dst IP addresses based on home server, and
* calculate and add the message-authenticator.
*
- * This is a distinct function from home_server_ldb, as not all home_server
+ * This is a distinct function from home_server_ldb, as not all home_server_t
* lookups result in the *CURRENT* request being proxied,
* as in rlm_replicate, and this may trigger asserts elsewhere in the
* server.
*/
-void home_server_update_request(home_server *home, REQUEST *request)
+void home_server_update_request(home_server_t *home, REQUEST *request)
{
/*
if (!request->proxy) {
request->proxy = rad_alloc(request, true);
if (!request->proxy) {
- ERROR("no memory");
+ ERROR("no memory");
fr_exit(1);
_exit(1);
}
request->proxy->src_port = 0;
request->proxy->dst_ipaddr = home->ipaddr;
request->proxy->dst_port = home->port;
+#ifdef WITH_TCP
+ request->proxy->proto = home->proto;
+#endif
request->home_server = home;
/*
* Access-Requests have a Message-Authenticator added,
* unless one already exists.
*/
- if ((request->packet->code == PW_AUTHENTICATION_REQUEST) &&
+ if ((request->packet->code == PW_CODE_AUTHENTICATION_REQUEST) &&
!pairfind(request->proxy->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY)) {
pairmake(request->proxy, &request->proxy->vps,
"Message-Authenticator", "0x00",
}
}
-home_server *home_server_ldb(char const *realmname,
+home_server_t *home_server_ldb(char const *realmname,
home_pool_t *pool, REQUEST *request)
{
int start;
int count;
- home_server *found = NULL;
- home_server *zombie = NULL;
+ home_server_t *found = NULL;
+ home_server_t *zombie = NULL;
VALUE_PAIR *vp;
/*
* Otherwise, use it.
*/
for (count = 0; count < pool->num_home_servers; count++) {
- home_server *home = pool->servers[(start + count) % pool->num_home_servers];
+ home_server_t *home = pool->servers[(start + count) % pool->num_home_servers];
if (!home) continue;
* there.
*/
if ((request->listener->type == RAD_LISTEN_DETAIL) &&
- (request->packet->code == PW_ACCOUNTING_REQUEST) &&
+ (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) &&
(fr_ipaddr_cmp(&home->ipaddr, &request->packet->src_ipaddr) == 0)) {
continue;
}
if (!found && pool->fallback) {
found = pool->fallback;
- WDEBUG("Home server pool %s failing over to fallback %s",
+ WARN("Home server pool %s failing over to fallback %s",
pool->name, found->server);
if (pool->in_fallback) goto update_and_return;
if (!realm_config->fallback &&
realm_config->wake_all_if_all_dead) {
for (count = 0; count < pool->num_home_servers; count++) {
- home_server *home = pool->servers[count];
+ home_server_t *home = pool->servers[count];
if (!home) continue;
if (!rd) return NULL;
pool = NULL;
- if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
+ if (request->packet->code == PW_CODE_AUTHENTICATION_REQUEST) {
pool = rd->auth_pool;
- } else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
+ } else if (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) {
pool = rd->acct_pool;
}
if (!pool) return NULL;
}
-home_server *home_server_find(fr_ipaddr_t *ipaddr, int port, int proto)
+home_server_t *home_server_find(fr_ipaddr_t *ipaddr, uint16_t port, int proto)
{
- home_server myhome;
+ home_server_t myhome;
memset(&myhome, 0, sizeof(myhome));
myhome.ipaddr = *ipaddr;
}
#ifdef WITH_COA
-home_server *home_server_byname(char const *name, int type)
+home_server_t *home_server_byname(char const *name, int type)
{
- home_server myhome;
+ home_server_t myhome;
memset(&myhome, 0, sizeof(myhome));
myhome.type = type;
#endif
#ifdef WITH_STATS
-home_server *home_server_bynumber(int number)
+home_server_t *home_server_bynumber(int number)
{
- home_server myhome;
+ home_server_t myhome;
memset(&myhome, 0, sizeof(myhome));
myhome.number = number;
/*
* End a session by faking a Stop packet to all accounting modules.
*/
-int session_zap(REQUEST *request, uint32_t nasaddr, unsigned int port,
+int session_zap(REQUEST *request, uint32_t nasaddr, uint32_t nas_port,
char const *user,
char const *sessionid, uint32_t cliaddr, char proto,
int session_time)
int ret;
stopreq = request_alloc_fake(request);
- stopreq->packet->code = PW_ACCOUNTING_REQUEST; /* just to be safe */
+ stopreq->packet->code = PW_CODE_ACCOUNTING_REQUEST; /* just to be safe */
stopreq->listener = request->listener;
rad_assert(stopreq != NULL);
INTPAIR(PW_ACCT_DELAY_TIME, 0);
STRINGPAIR(PW_USER_NAME, user);
userpair = vp;
- INTPAIR(PW_NAS_PORT, port);
+ INTPAIR(PW_NAS_PORT, nas_port);
STRINGPAIR(PW_ACCT_SESSION_ID, sessionid);
if(proto == 'P') {
INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
* 1 The user is logged in.
* 2 Some error occured.
*/
-int rad_check_ts(uint32_t nasaddr, unsigned int portnum, char const *user,
+int rad_check_ts(uint32_t nasaddr, uint32_t nas_port, char const *user,
char const *session_id)
{
pid_t pid, child_pid;
closefrom(3);
ip_ntoa(address, nasaddr);
- snprintf(port, 11, "%u", portnum);
+ snprintf(port, 11, "%u", nas_port);
#ifdef __EMX__
/* OS/2 can't directly execute scripts then we call the command
execl(getenv("COMSPEC"), "", "/C","checkrad", cl->nas_type, address, port,
user, session_id, NULL);
#else
- execl(mainconfig.checkrad, "checkrad", cl->nas_type, address, port,
+ execl(main_config.checkrad, "checkrad", cl->nas_type, address, port,
user, session_id, NULL);
#endif
- ERROR("Check-TS: exec %s: %s", mainconfig.checkrad, strerror(errno));
+ ERROR("Check-TS: exec %s: %s", main_config.checkrad, fr_syserror(errno));
/*
* Exit - 2 means "some error occured".
return 2;
}
#else
-int rad_check_ts(UNUSED uint32_t nasaddr, UNUSED unsigned int portnum,
+int rad_check_ts(UNUSED uint32_t nasaddr, UNUSED unsigned int nas_port,
UNUSED char const *user, UNUSED char const *session_id)
{
ERROR("Simultaneous-Use is not supported");
#else
/* WITH_SESSION_MGMT */
-int session_zap(UNUSED REQUEST *request, UNUSED uint32_t nasaddr, UNUSED unsigned int port,
+int session_zap(UNUSED REQUEST *request, UNUSED uint32_t nasaddr, UNUSED uint32_t nas_port,
UNUSED char const *user,
UNUSED char const *sessionid, UNUSED uint32_t cliaddr, UNUSED char proto,
UNUSED int session_time)
return RLM_MODULE_FAIL;
}
-int rad_check_ts(UNUSED uint32_t nasaddr, UNUSED unsigned int portnum,
+int rad_check_ts(UNUSED uint32_t nasaddr, UNUSED unsigned int nas_port,
UNUSED char const *user, UNUSED char const *session_id)
{
ERROR("Simultaneous-Use is not supported");
#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/soh.h>
+#include <freeradius-devel/rad_assert.h>
/*
* This code implements parsing of MS-SOH data into FreeRadius AVPs
* @param data_len length of blob
* @return 1 on success, 0 on failure
*/
-static int eapsoh_mstlv(REQUEST *request, uint8_t const *p, unsigned int data_len) {
+static int CC_HINT(nonnull) eapsoh_mstlv(REQUEST *request, uint8_t const *p, unsigned int data_len) {
VALUE_PAIR *vp;
uint8_t c;
int t;
soh_tlv tlv;
int curr_shid=-1, curr_shid_c=-1, curr_hc=-1;
+ rad_assert(request->packet != NULL);
+
hdr.tlv_type = soh_pull_be_16(data); data += 2;
hdr.tlv_len = soh_pull_be_16(data); data += 2;
hdr.tlv_vendor = soh_pull_be_32(data); data += 4;
(request->listener->type != RAD_LISTEN_AUTH)) return;
/* don't count statistic requests */
- if (request->packet->code == PW_STATUS_SERVER)
+ if (request->packet->code == PW_CODE_STATUS_SERVER)
return;
#undef INC_AUTH
* deleted, because only the main server thread calls
* this function, which makes it thread-safe.
*/
- if (request->reply) switch (request->reply->code) {
- case PW_AUTHENTICATION_ACK:
+ if (request->reply && (request->packet->code != PW_CODE_STATUS_SERVER)) switch (request->reply->code) {
+ case PW_CODE_AUTHENTICATION_ACK:
INC_AUTH(total_access_accepts);
auth_stats:
&request->reply->timestamp);
break;
- case PW_AUTHENTICATION_REJECT:
+ case PW_CODE_AUTHENTICATION_REJECT:
INC_AUTH(total_access_rejects);
goto auth_stats;
- case PW_ACCESS_CHALLENGE:
+ case PW_CODE_ACCESS_CHALLENGE:
INC_AUTH(total_access_challenges);
goto auth_stats;
#ifdef WITH_ACCOUNTING
- case PW_ACCOUNTING_RESPONSE:
+ case PW_CODE_ACCOUNTING_RESPONSE:
INC_ACCT(total_responses);
stats_time(&radius_acct_stats,
&request->packet->timestamp,
#endif
#ifdef WITH_COA
- case PW_COA_ACK:
+ case PW_CODE_COA_ACK:
INC_COA(total_access_accepts);
coa_stats:
INC_COA(total_responses);
&request->reply->timestamp);
break;
- case PW_COA_NAK:
+ case PW_CODE_COA_NAK:
INC_COA(total_access_rejects);
goto coa_stats;
- case PW_DISCONNECT_ACK:
+ case PW_CODE_DISCONNECT_ACK:
INC_DSC(total_access_accepts);
dsc_stats:
INC_DSC(total_responses);
&request->reply->timestamp);
break;
- case PW_DISCONNECT_NAK:
+ case PW_CODE_DISCONNECT_NAK:
INC_DSC(total_access_rejects);
goto dsc_stats;
#endif
* authenticator.
*/
case 0:
- if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
+ if (request->packet->code == PW_CODE_AUTHENTICATION_REQUEST) {
if (request->reply->offset == -2) {
INC_AUTH(total_bad_authenticators);
} else {
INC_AUTH(total_packets_dropped);
}
- } else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
+ } else if (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) {
if (request->reply->offset == -2) {
INC_ACCT(total_bad_authenticators);
} else {
if (!request->proxy || !request->proxy_listener) goto done; /* simplifies formatting */
switch (request->proxy->code) {
- case PW_AUTHENTICATION_REQUEST:
+ case PW_CODE_AUTHENTICATION_REQUEST:
proxy_auth_stats.total_requests += request->num_proxied_requests;
request->proxy_listener->stats.total_requests += request->num_proxied_requests;
request->home_server->stats.total_requests += request->num_proxied_requests;
break;
#ifdef WITH_ACCOUNTING
- case PW_ACCOUNTING_REQUEST:
+ case PW_CODE_ACCOUNTING_REQUEST:
proxy_acct_stats.total_requests++;
request->proxy_listener->stats.total_requests += request->num_proxied_requests;
request->home_server->stats.total_requests += request->num_proxied_requests;
#define INC(_x) proxy_auth_stats._x += request->num_proxied_responses; request->proxy_listener->stats._x += request->num_proxied_responses; request->home_server->stats._x += request->num_proxied_responses;
switch (request->proxy_reply->code) {
- case PW_AUTHENTICATION_ACK:
+ case PW_CODE_AUTHENTICATION_ACK:
INC(total_access_accepts);
proxy_stats:
INC(total_responses);
&request->proxy_reply->timestamp);
break;
- case PW_AUTHENTICATION_REJECT:
+ case PW_CODE_AUTHENTICATION_REJECT:
INC(total_access_rejects);
goto proxy_stats;
- case PW_ACCESS_CHALLENGE:
+ case PW_CODE_ACCESS_CHALLENGE:
INC(total_access_challenges);
goto proxy_stats;
#ifdef WITH_ACCOUNTING
- case PW_ACCOUNTING_RESPONSE:
+ case PW_CODE_ACCOUNTING_RESPONSE:
proxy_acct_stats.total_responses++;
request->proxy_listener->stats.total_responses++;
request->home_server->stats.total_responses++;
VALUE_PAIR *vp;
for (i = 0; table[i].attribute != 0; i++) {
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
table[i].attribute, VENDORPEC_FREERADIUS);
if (!vp) continue;
/*
* Statistics are available ONLY on a "status" port.
*/
- rad_assert(request->packet->code == PW_STATUS_SERVER);
+ rad_assert(request->packet->code == PW_CODE_STATUS_SERVER);
rad_assert(request->listener->type == RAD_LISTEN_NONE);
flag = pairfind(request->packet->vps, 127, VENDORPEC_FREERADIUS, TAG_ANY);
* Internal server statistics
*/
if ((flag->vp_integer & 0x10) != 0) {
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
176, VENDORPEC_FREERADIUS);
if (vp) vp->vp_date = start_time.tv_sec;
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
177, VENDORPEC_FREERADIUS);
if (vp) vp->vp_date = hup_time.tv_sec;
thread_pool_queue_stats(array, pps);
for (i = 0; i <= 4; i++) {
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
162 + i, VENDORPEC_FREERADIUS);
if (!vp) continue;
}
for (i = 0; i < 2; i++) {
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
181 + i, VENDORPEC_FREERADIUS);
if (!vp) continue;
*/
if ((vp->da->type == PW_TYPE_INTEGER) &&
(client->ipaddr.af == AF_INET)) {
- vp = radius_paircreate(request,
+ vp = radius_paircreate(request->reply,
&request->reply->vps,
167, VENDORPEC_FREERADIUS);
if (vp) {
vp->vp_ipaddr = client->ipaddr.ipaddr.ip4addr.s_addr;
}
- if (client->prefix != 32) {
- vp = radius_paircreate(request,
+ if (client->ipaddr.prefix != 32) {
+ vp = radius_paircreate(request->reply,
&request->reply->vps,
169, VENDORPEC_FREERADIUS);
if (vp) {
- vp->vp_integer = client->prefix;
+ vp->vp_integer = client->ipaddr.prefix;
}
}
}
*/
if (((flag->vp_integer & 0x80) != 0) &&
((flag->vp_integer & 0x03) != 0)) {
- home_server *home;
+ home_server_t *home;
VALUE_PAIR *server_ip, *server_port;
fr_ipaddr_t ipaddr;
pairadd(&request->reply->vps,
paircopyvp(request->reply, server_port));
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
172, VENDORPEC_FREERADIUS);
if (vp) vp->vp_integer = home->currently_outstanding;
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
173, VENDORPEC_FREERADIUS);
if (vp) vp->vp_integer = home->state;
if ((home->state == HOME_STATE_ALIVE) &&
(home->revive_time.tv_sec != 0)) {
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
175, VENDORPEC_FREERADIUS);
if (vp) vp->vp_date = home->revive_time.tv_sec;
}
if ((home->state == HOME_STATE_ALIVE) &&
(home->ema.window > 0)) {
- vp = radius_paircreate(request,
+ vp = radius_paircreate(request->reply,
&request->reply->vps,
178, VENDORPEC_FREERADIUS);
if (vp) vp->vp_integer = home->ema.window;
- vp = radius_paircreate(request,
+ vp = radius_paircreate(request->reply,
&request->reply->vps,
179, VENDORPEC_FREERADIUS);
if (vp) vp->vp_integer = home->ema.ema1 / EMA_SCALE;
- vp = radius_paircreate(request,
+ vp = radius_paircreate(request->reply,
&request->reply->vps,
180, VENDORPEC_FREERADIUS);
if (vp) vp->vp_integer = home->ema.ema10 / EMA_SCALE;
}
if (home->state == HOME_STATE_IS_DEAD) {
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
174, VENDORPEC_FREERADIUS);
if (vp) vp->vp_date = home->zombie_period_start.tv_sec + home->zombie_period;
}
*
* FIXME: do this for clients, too!
*/
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
184, VENDORPEC_FREERADIUS);
if (vp) vp->vp_date = home->last_packet_recv;
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
185, VENDORPEC_FREERADIUS);
if (vp) vp->vp_date = home->last_packet_sent;
#ifdef WITH_STATS
typedef struct fr_pps_t {
- int pps_old;
- int pps_now;
- int pps;
- time_t time_old;
+ uint32_t pps_old;
+ uint32_t pps_now;
+ uint32_t pps;
+ time_t time_old;
} fr_pps_t;
#endif
*/
typedef struct THREAD_POOL {
#ifndef WITH_GCD
- THREAD_HANDLE *head;
- THREAD_HANDLE *tail;
-
- int active_threads; /* protected by queue_mutex */
- int exited_threads;
- int total_threads;
- int max_thread_num;
- int start_threads;
- int max_threads;
- int min_spare_threads;
- int max_spare_threads;
- unsigned int max_requests_per_thread;
- unsigned long request_count;
- time_t time_last_spawned;
- int cleanup_delay;
- int stop_flag;
+ THREAD_HANDLE *head;
+ THREAD_HANDLE *tail;
+
+ uint32_t active_threads; /* protected by queue_mutex */
+ uint32_t total_threads;
+
+ uint32_t exited_threads;
+ uint32_t max_thread_num;
+ uint32_t start_threads;
+ uint32_t max_threads;
+ uint32_t min_spare_threads;
+ uint32_t max_spare_threads;
+ uint32_t max_requests_per_thread;
+ uint32_t request_count;
+ time_t time_last_spawned;
+ uint32_t cleanup_delay;
+ bool stop_flag;
#endif /* WITH_GCD */
- int spawn_flag;
+ bool spawn_flag;
#ifdef WNOHANG
pthread_mutex_t wait_mutex;
*/
pthread_mutex_t queue_mutex;
- int max_queue_size;
- int num_queued;
+ uint32_t max_queue_size;
+ uint32_t num_queued;
fr_fifo_t *fifo[NUM_FIFOS];
#endif /* WITH_GCD */
} THREAD_POOL;
static THREAD_POOL thread_pool;
-static int pool_initialized = false;
+static bool pool_initialized = false;
#ifndef WITH_GCD
static time_t last_cleaned = 0;
* A mapping of configuration file names to internal integers
*/
static const CONF_PARSER thread_config[] = {
- { "start_servers", PW_TYPE_INTEGER, 0, &thread_pool.start_threads, "5" },
- { "max_servers", PW_TYPE_INTEGER, 0, &thread_pool.max_threads, "32" },
- { "min_spare_servers", PW_TYPE_INTEGER, 0, &thread_pool.min_spare_threads, "3" },
- { "max_spare_servers", PW_TYPE_INTEGER, 0, &thread_pool.max_spare_threads, "10" },
- { "max_requests_per_server", PW_TYPE_INTEGER, 0, &thread_pool.max_requests_per_thread, "0" },
- { "cleanup_delay", PW_TYPE_INTEGER, 0, &thread_pool.cleanup_delay, "5" },
- { "max_queue_size", PW_TYPE_INTEGER, 0, &thread_pool.max_queue_size, "65536" },
+ { "start_servers", FR_CONF_POINTER(PW_TYPE_INTEGER, &thread_pool.start_threads), "5" },
+ { "max_servers", FR_CONF_POINTER(PW_TYPE_INTEGER, &thread_pool.max_threads), "32" },
+ { "min_spare_servers", FR_CONF_POINTER(PW_TYPE_INTEGER, &thread_pool.min_spare_threads), "3" },
+ { "max_spare_servers", FR_CONF_POINTER(PW_TYPE_INTEGER, &thread_pool.max_spare_threads), "10" },
+ { "max_requests_per_server", FR_CONF_POINTER(PW_TYPE_INTEGER, &thread_pool.max_requests_per_thread), "0" },
+ { "cleanup_delay", FR_CONF_POINTER(PW_TYPE_INTEGER, &thread_pool.cleanup_delay), "5" },
+ { "max_queue_size", FR_CONF_POINTER(PW_TYPE_INTEGER, &thread_pool.max_queue_size), "65536" },
#ifdef WITH_STATS
#ifdef WITH_ACCOUNTING
- { "auto_limit_acct", PW_TYPE_BOOLEAN, 0, &thread_pool.auto_limit_acct, NULL },
+ { "auto_limit_acct", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &thread_pool.auto_limit_acct), NULL },
#endif
#endif
{ NULL, -1, 0, NULL, NULL }
{
int i;
-#ifdef HAVE_OPENSSL_EVP_H
- /*
- * Enable all ciphers and digests.
- */
- OpenSSL_add_all_algorithms();
-#endif
-
ssl_mutexes = rad_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
if (!ssl_mutexes) {
ERROR("Error allocating memory for SSL mutexes!");
*/
int request_enqueue(REQUEST *request)
{
+ rad_assert(pool_initialized == true);
+
/*
* If we haven't checked the number of child threads
* in a while, OR if the thread pool appears to be full,
* A probabilistic approach allows us to process
* SOME of the new accounting packets.
*/
- if ((request->packet->code == PW_ACCOUNTING_REQUEST) &&
+ if ((request->packet->code == PW_CODE_ACCOUNTING_REQUEST) &&
(thread_pool.num_queued > (thread_pool.max_queue_size / 2)) &&
(thread_pool.pps_in.pps_now > thread_pool.pps_out.pps_now)) {
uint32_t prob;
- int keep;
+ uint32_t keep;
/*
* Take a random value of how full we
thread_pool.request_count++;
if (thread_pool.num_queued >= thread_pool.max_queue_size) {
- int complain = false;
- time_t now;
- static time_t last_complained = 0;
-
- now = time(NULL);
- if (last_complained != now) {
- last_complained = now;
- complain = true;
- }
-
pthread_mutex_unlock(&thread_pool.queue_mutex);
/*
* Mark the request as done.
*/
- if (complain) {
- ERROR("Something is blocking the server. There are %d packets in the queue, waiting to be processed. Ignoring the new request.", thread_pool.max_queue_size);
- }
+ RATE_LIMIT(ERROR("Something is blocking the server. There are %d packets in the queue, "
+ "waiting to be processed. Ignoring the new request.", thread_pool.num_queued));
return 0;
}
request->component = "<core>";
request->module = "<queue>";
+ request->child_state = REQUEST_QUEUED;
/*
* Push the request onto the appropriate fifo for that
REQUEST *request;
reap_children();
+ rad_assert(pool_initialized == true);
+
pthread_mutex_lock(&thread_pool.queue_mutex);
#ifdef WITH_STATS
request->component = "<core>";
request->module = "";
+ request->child_state = REQUEST_RUNNING;
/*
* If the request has sat in the queue for too long,
thread_pool.active_threads++;
blocked = time(NULL);
- if ((blocked - request->timestamp) > 5) {
+ if (!request->proxy && (blocked - request->timestamp) > 5) {
total_blocked++;
if (last_complained < blocked) {
last_complained = blocked;
goto re_wait;
}
ERROR("Thread %d failed waiting for semaphore: %s: Exiting\n",
- self->thread_num, strerror(errno));
+ self->thread_num, fr_syserror(errno));
break;
}
DEBUG2("Thread %d got semaphore", self->thread_num);
#ifdef HAVE_OPENSSL_ERR_H
- /*
+ /*
* Clear the error queue for the current thread.
*/
ERR_clear_error ();
self->request_count);
#ifdef WITH_ACCOUNTING
- if ((self->request->packet->code == PW_ACCOUNTING_REQUEST) &&
+ if ((self->request->packet->code == PW_CODE_ACCOUNTING_REQUEST) &&
thread_pool.auto_limit_acct) {
VALUE_PAIR *vp;
REQUEST *request = self->request;
rcode = pthread_create(&handle->pthread_id, 0,
request_handler_thread, handle);
if (rcode != 0) {
+ free(handle);
ERROR("Thread create failed: %s",
- strerror(rcode));
+ fr_syserror(rcode));
return NULL;
}
*
* FIXME: What to do on a SIGHUP???
*/
-int thread_pool_init(UNUSED CONF_SECTION *cs, int *spawn_flag)
+int thread_pool_init(UNUSED CONF_SECTION *cs, bool *spawn_flag)
{
#ifndef WITH_GCD
- int i, rcode;
+ uint32_t i;
+ int rcode;
CONF_SECTION *pool_cf;
#endif
time_t now;
thread_pool.total_threads = 0;
thread_pool.max_thread_num = 1;
thread_pool.cleanup_delay = 5;
- thread_pool.stop_flag = 0;
+ thread_pool.stop_flag = false;
#endif
thread_pool.spawn_flag = *spawn_flag;
#ifdef WNOHANG
if ((pthread_mutex_init(&thread_pool.wait_mutex,NULL) != 0)) {
ERROR("FATAL: Failed to initialize wait mutex: %s",
- strerror(errno));
+ fr_syserror(errno));
return -1;
}
ERROR("FATAL: max_queue_size value must be in range 2-1048576");
return -1;
}
+
+ if (thread_pool.start_threads > thread_pool.max_threads) {
+ ERROR("FATAL: start_servers (%i) must be <= max_servers (%i)",
+ thread_pool.start_threads, thread_pool.max_threads);
+ return -1;
+ }
#endif /* WITH_GCD */
/*
rcode = sem_init(&thread_pool.semaphore, 0, SEMAPHORE_LOCKED);
if (rcode != 0) {
ERROR("FATAL: Failed to initialize semaphore: %s",
- strerror(errno));
+ fr_syserror(errno));
return -1;
}
rcode = pthread_mutex_init(&thread_pool.queue_mutex,NULL);
if (rcode != 0) {
ERROR("FATAL: Failed to initialize queue mutex: %s",
- strerror(errno));
+ fr_syserror(errno));
return -1;
}
#else
thread_pool.queue = dispatch_queue_create("org.freeradius.threads", NULL);
if (!thread_pool.queue) {
- ERROR("Failed creating dispatch queue: %s", strerror(errno));
+ ERROR("Failed creating dispatch queue: %s", fr_syserror(errno));
fr_exit(1);
}
#endif
THREAD_HANDLE *handle;
THREAD_HANDLE *next;
+ if (!pool_initialized) return;
+
/*
* Set pool stop flag.
*/
- thread_pool.stop_flag = 1;
+ thread_pool.stop_flag = true;
/*
* Wakeup all threads to make them see stop flag.
*/
static void thread_pool_manage(time_t now)
{
- int spare;
+ uint32_t spare;
int i, total;
THREAD_HANDLE *handle, *next;
- int active_threads;
+ uint32_t active_threads;
/*
* Loop over the thread pool, deleting exited threads.
active_threads = thread_pool.active_threads;
spare = thread_pool.total_threads - active_threads;
if (debug_flag) {
- static int old_total = -1;
- static int old_active = -1;
+ static uint32_t old_total = 0;
+ static uint32_t old_active = 0;
- if ((old_total != thread_pool.total_threads) ||
- (old_active != active_threads)) {
+ if ((old_total != thread_pool.total_threads) || (old_active != active_threads)) {
DEBUG2("Threads: total/active/spare threads = %d/%d/%d",
- thread_pool.total_threads, active_threads, spare);
+ thread_pool.total_threads, active_threads, spare);
old_total = thread_pool.total_threads;
old_active = active_threads;
}
* passed since we last created one. This helps to minimize
* the amount of create/delete cycles.
*/
- if ((now - thread_pool.time_last_spawned) < thread_pool.cleanup_delay) {
+ if ((now - thread_pool.time_last_spawned) < (int)thread_pool.cleanup_delay) {
return;
}
* Use global "trigger" section if no local config is given.
*/
if (!cs) {
- cs = mainconfig.config;
+ cs = main_config.config;
attr = name;
} else {
/*
* reference to the full path, rather than the sub-path.
*/
subcs = cf_section_sub_find(cs, "trigger");
- if (!subcs && (cs != mainconfig.config)) {
- subcs = cf_section_sub_find(mainconfig.config, "trigger");
+ if (!subcs && (cs != main_config.config)) {
+ subcs = cf_section_sub_find(main_config.config, "trigger");
attr = name;
}
if (!subcs) return;
- ci = cf_reference_item(subcs, mainconfig.config, attr);
+ ci = cf_reference_item(subcs, main_config.config, attr);
if (!ci) {
- RDEBUG3("No such item in trigger section: %s", attr);
+ ERROR("No such item in trigger section: %s", attr);
return;
}
if (!cf_item_is_pair(ci)) {
- RDEBUG2("Trigger is not a configuration variable: %s", attr);
+ ERROR("Trigger is not a configuration variable: %s", attr);
return;
}
value = cf_pair_value(cp);
if (!value) {
- RDEBUG2("Trigger has no value: %s", name);
+ ERROR("Trigger has no value: %s", name);
return;
}
}
}
- RDEBUG("Trigger %s -> %s", name, value);
+ DEBUG("Trigger %s -> %s", name, value);
radius_exec_program(request, value, false, true, NULL, 0, EXEC_TIMEOUT, vp, NULL);
}
#include <openssl/ocsp.h>
#endif
-static void tls_server_conf_free(fr_tls_server_conf_t *conf);
+typedef struct libssl_defect {
+ uint64_t high;
+ uint64_t low;
+
+ char const *id;
+ char const *name;
+ char const *comment;
+} libssl_defect_t;
+
+/* Record critical defects in libssl here (newest first)*/
+static libssl_defect_t libssl_defects[] =
+{
+ {
+ .low = 0x010001000, /* 1.0.1 */
+ .high = 0x01000106f, /* 1.0.1f */
+ .id = "CVE-2014-0160",
+ .name = "Heartbleed",
+ .comment = "For more information see http://heartbleed.com"
+ }
+};
/* record */
static void record_init(record_t *buf);
{
int verify_mode;
tls_session_t *ssn = NULL;
+ REQUEST *request;
ssn = talloc_zero(conf, tls_session_t);
if (!ssn) return NULL;
ssn->ctx = conf->ctx;
+
+ SSL_CTX_set_mode(ssn->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_AUTO_RETRY);
+
ssn->ssl = SSL_new(ssn->ctx);
- rad_assert(ssn->ssl != NULL);
+ if (!ssn->ssl) {
+ talloc_free(ssn);
+ return NULL;
+ }
+
+ request = talloc_zero(ssn, REQUEST);
+ SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_REQUEST, (void *)request);
/*
* Add the message callback to identify what type of
if (SSL_connect(ssn->ssl) <= 0) {
int err;
while ((err = ERR_get_error())) {
- DEBUG("OpenSSL Err says %s",
- ERR_error_string(err, NULL));
+ ERROR("tls: %s", ERR_error_string(err, NULL));
}
+ SSL_free(ssn->ssl);
talloc_free(ssn);
+
return NULL;
}
* FIXME: Also do it every N sessions?
*/
if (conf->session_cache_enable &&
- ((conf->session_last_flushed + (conf->session_timeout * 1800)) <= request->timestamp)){
+ ((conf->session_last_flushed + ((int)conf->session_timeout * 1800)) <= request->timestamp)){
RDEBUG2("Flushing SSL sessions (of #%ld)",
SSL_CTX_sess_number(conf->ctx));
{
int err;
+ if (ssn->invalid_hb_used) return 0;
+
err = BIO_write(ssn->into_ssl, ssn->dirty_in.data, ssn->dirty_in.used);
if (err != (int) ssn->dirty_in.used) {
RDEBUG("Failed writing %d to SSL BIO: %d", ssn->dirty_in.used,
if (SSL_is_init_finished(ssn->ssl)) {
DEBUG2("SSL Connection Established\n");
}
- if (SSL_in_init(ssn->ssl)) {
+ if (SSL_in_init(ssn->ssl)) {
DEBUG2("In SSL Handshake Phase\n");
}
- if (SSL_in_before(ssn->ssl)) {
+ if (SSL_in_before(ssn->ssl)) {
DEBUG2("Before SSL Handshake Phase\n");
}
- if (SSL_in_accept_init(ssn->ssl)) {
+ if (SSL_in_accept_init(ssn->ssl)) {
DEBUG2("In SSL Accept mode \n");
}
- if (SSL_in_connect_init(ssn->ssl)) {
+ if (SSL_in_connect_init(ssn->ssl)) {
DEBUG2("In SSL Connect mode \n");
}
}
/*
- * Take clear-text user data, and encrypt it into the output buffer,
+ * Take cleartext user data, and encrypt it into the output buffer,
* to send to the client at the other end of the SSL connection.
*/
int tls_handshake_send(REQUEST *request, tls_session_t *ssn)
SSL_set_quiet_shutdown(ssn->ssl, 1);
SSL_shutdown(ssn->ssl);
- if(ssn->ssl)
+ if (ssn->ssl) {
SSL_free(ssn->ssl);
+ ssn->ssl = NULL;
+ }
record_close(&ssn->clean_in);
record_close(&ssn->clean_out);
str_details1, str_details2);
request = SSL_get_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST);
-
- RDEBUG2("%s\n", tls_session->info.info_description);
+ if (request) {
+ RDEBUG2("%s", tls_session->info.info_description);
+ } else {
+ DEBUG2("%s", tls_session->info.info_description);
+ }
}
static CONF_PARSER cache_config[] = {
- { "enable", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, session_cache_enable), NULL, "no" },
- { "lifetime", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, session_timeout), NULL, "24" },
- { "max_entries", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, session_cache_size), NULL, "255" },
- { "name", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, session_id_name), NULL, NULL},
- { "persist_dir", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, session_cache_path), NULL, NULL},
+ { "enable", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, session_cache_enable), "no" },
+ { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, session_timeout), "24" },
+ { "max_entries", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, session_cache_size), "255" },
+ { "name", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, session_id_name), NULL },
+ { "persist_dir", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, session_cache_path), NULL },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
static CONF_PARSER verify_config[] = {
- { "tmpdir", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, verify_tmp_dir), NULL, NULL},
- { "client", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, verify_client_cert_cmd), NULL, NULL},
+ { "tmpdir", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, verify_tmp_dir), NULL },
+ { "client", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, verify_client_cert_cmd), NULL },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
#ifdef HAVE_OPENSSL_OCSP_H
static CONF_PARSER ocsp_config[] = {
- { "enable", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, ocsp_enable), NULL, "no"},
- { "override_cert_url", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, ocsp_override_url), NULL, "no"},
- { "url", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, ocsp_url), NULL, NULL },
- { "use_nonce", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, ocsp_use_nonce), NULL, "yes"},
- { "timeout", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, ocsp_timeout), NULL, "yes"},
- { "softfail", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, ocsp_softfail), NULL, "yes"},
+ { "enable", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, ocsp_enable), "no" },
+ { "override_cert_url", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, ocsp_override_url), "no" },
+ { "url", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, ocsp_url), NULL },
+ { "use_nonce", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, ocsp_use_nonce), "yes" },
+ { "timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, ocsp_timeout), "yes" },
+ { "softfail", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, ocsp_softfail), "yes" },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
#endif
static CONF_PARSER tls_server_config[] = {
- { "rsa_key_exchange", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, rsa_key), NULL, "no" },
- { "dh_key_exchange", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, dh_key), NULL, "yes" },
- { "rsa_key_length", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, rsa_key_length), NULL, "512" },
- { "dh_key_length", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, dh_key_length), NULL, "512" },
- { "verify_depth", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, verify_depth), NULL, "0" },
- { "CA_path", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED,
- offsetof(fr_tls_server_conf_t, ca_path), NULL, NULL },
- { "ca_path", PW_TYPE_FILE_INPUT,
- offsetof(fr_tls_server_conf_t, ca_path), NULL, NULL },
- { "pem_file_type", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, file_type), NULL, "yes" },
- { "private_key_file", PW_TYPE_FILE_INPUT,
- offsetof(fr_tls_server_conf_t, private_key_file), NULL, NULL },
- { "certificate_file", PW_TYPE_FILE_INPUT,
- offsetof(fr_tls_server_conf_t, certificate_file), NULL, NULL },
- { "CA_file", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED,
- offsetof(fr_tls_server_conf_t, ca_file), NULL, NULL },
- { "ca_file", PW_TYPE_FILE_INPUT,
- offsetof(fr_tls_server_conf_t, ca_file), NULL, NULL },
- { "private_key_password", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, private_key_password), NULL, NULL },
+ { "rsa_key_exchange", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, rsa_key), "no" },
+ { "dh_key_exchange", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, dh_key), "yes" },
+ { "rsa_key_length", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, rsa_key_length), "512" },
+ { "dh_key_length", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, dh_key_length), "512" },
+ { "verify_depth", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, verify_depth), "0" },
+ { "CA_path", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, fr_tls_server_conf_t, ca_path), NULL },
+ { "ca_path", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, ca_path), NULL },
+ { "pem_file_type", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, file_type), "yes" },
+ { "private_key_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, private_key_file), NULL },
+ { "certificate_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, certificate_file), NULL },
+ { "CA_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, fr_tls_server_conf_t, ca_file), NULL },
+ { "ca_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, ca_file), NULL },
+ { "private_key_password", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, fr_tls_server_conf_t, private_key_password), NULL },
#ifdef PSK_MAX_IDENTITY_LEN
- { "psk_identity", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, psk_identity), NULL, NULL },
- { "psk_hexphrase", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, psk_password), NULL, NULL },
+ { "psk_identity", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, psk_identity), NULL },
+ { "psk_hexphrase", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, fr_tls_server_conf_t, psk_password), NULL },
#endif
- { "dh_file", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, dh_file), NULL, NULL },
- { "random_file", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, random_file), NULL, NULL },
- { "fragment_size", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, fragment_size), NULL, "1024" },
- { "include_length", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, include_length), NULL, "yes" },
- { "check_crl", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, check_crl), NULL, "no"},
- { "allow_expired_crl", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, allow_expired_crl), NULL, NULL},
- { "check_cert_cn", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, check_cert_cn), NULL, NULL},
- { "cipher_list", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, cipher_list), NULL, NULL},
- { "check_cert_issuer", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, check_cert_issuer), NULL, NULL},
- { "require_client_cert", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, require_client_cert), NULL, NULL },
+ { "dh_file", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, dh_file), NULL },
+ { "random_file", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, random_file), NULL },
+ { "fragment_size", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, fragment_size), "1024" },
+ { "include_length", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, include_length), "yes" },
+ { "check_crl", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, check_crl), "no" },
+ { "allow_expired_crl", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, allow_expired_crl), NULL },
+ { "check_cert_cn", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, check_cert_cn), NULL },
+ { "cipher_list", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, cipher_list), NULL },
+ { "check_cert_issuer", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, check_cert_issuer), NULL },
+ { "require_client_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, require_client_cert), NULL },
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
#ifndef OPENSSL_NO_ECDH
- { "ecdh_curve", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, ecdh_curve), NULL, "prime256v1"},
+ { "ecdh_curve", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, ecdh_curve), "prime256v1" },
#endif
#endif
- { "cache", PW_TYPE_SUBSECTION, 0, NULL, (void const *) cache_config },
+ { "cache", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) cache_config },
- { "verify", PW_TYPE_SUBSECTION, 0, NULL, (void const *) verify_config },
+ { "verify", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) verify_config },
#ifdef HAVE_OPENSSL_OCSP_H
- { "ocsp", PW_TYPE_SUBSECTION, 0, NULL, (void const *) ocsp_config },
+ { "ocsp", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) ocsp_config },
#endif
{ NULL, -1, 0, NULL, NULL } /* end the list */
static CONF_PARSER tls_client_config[] = {
- { "rsa_key_exchange", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, rsa_key), NULL, "no" },
- { "dh_key_exchange", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, dh_key), NULL, "yes" },
- { "rsa_key_length", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, rsa_key_length), NULL, "512" },
- { "dh_key_length", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, dh_key_length), NULL, "512" },
- { "verify_depth", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, verify_depth), NULL, "0" },
- { "ca_path", PW_TYPE_FILE_INPUT,
- offsetof(fr_tls_server_conf_t, ca_path), NULL, NULL },
- { "pem_file_type", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, file_type), NULL, "yes" },
- { "private_key_file", PW_TYPE_FILE_INPUT,
- offsetof(fr_tls_server_conf_t, private_key_file), NULL, NULL },
- { "certificate_file", PW_TYPE_FILE_INPUT,
- offsetof(fr_tls_server_conf_t, certificate_file), NULL, NULL },
- { "ca_file", PW_TYPE_FILE_INPUT,
- offsetof(fr_tls_server_conf_t, ca_file), NULL, NULL },
- { "private_key_password", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, private_key_password), NULL, NULL },
-#ifdef PSK_MAX_IDENTITY_LEN
- { "psk_identity", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, psk_identity), NULL, NULL },
- { "psk_hexphrase", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, psk_password), NULL, NULL },
-#endif
- { "dh_file", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, dh_file), NULL, NULL },
- { "random_file", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, random_file), NULL, NULL },
- { "fragment_size", PW_TYPE_INTEGER,
- offsetof(fr_tls_server_conf_t, fragment_size), NULL, "1024" },
- { "include_length", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, include_length), NULL, "yes" },
- { "check_crl", PW_TYPE_BOOLEAN,
- offsetof(fr_tls_server_conf_t, check_crl), NULL, "no"},
- { "check_cert_cn", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, check_cert_cn), NULL, NULL},
- { "cipher_list", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, cipher_list), NULL, NULL},
- { "check_cert_issuer", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, check_cert_issuer), NULL, NULL},
+ { "rsa_key_exchange", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, rsa_key), "no" },
+ { "dh_key_exchange", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, dh_key), "yes" },
+ { "rsa_key_length", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, rsa_key_length), "512" },
+ { "dh_key_length", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, dh_key_length), "512" },
+ { "verify_depth", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, verify_depth), "0" },
+ { "ca_path", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, ca_path), NULL },
+ { "pem_file_type", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, file_type), "yes" },
+ { "private_key_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, private_key_file), NULL },
+ { "certificate_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, certificate_file), NULL },
+ { "ca_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, ca_file), NULL },
+ { "private_key_password", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, fr_tls_server_conf_t, private_key_password), NULL },
+ { "dh_file", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, dh_file), NULL },
+ { "random_file", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, random_file), NULL },
+ { "fragment_size", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, fragment_size), "1024" },
+ { "include_length", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, include_length), "yes" },
+ { "check_crl", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, check_crl), "no" },
+ { "check_cert_cn", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, check_cert_cn), NULL },
+ { "cipher_list", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, cipher_list), NULL },
+ { "check_cert_issuer", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, check_cert_issuer), NULL },
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
#ifndef OPENSSL_NO_ECDH
- { "ecdh_curve", PW_TYPE_STRING_PTR,
- offsetof(fr_tls_server_conf_t, ecdh_curve), NULL, "prime256v1"},
+ { "ecdh_curve", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, ecdh_curve), "prime256v1" },
#endif
#endif
- { NULL, -1, 0, NULL, NULL } /* end the list */
+ { NULL, -1, 0, NULL, NULL } /* end the list */
};
DH *dh = NULL;
BIO *bio;
+ if (!file) return 0;
+
if ((bio = BIO_new_file(file, "r")) == NULL) {
ERROR("tls: Unable to open DH file - %s", file);
return -1;
dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
BIO_free(bio);
if (!dh) {
- WDEBUG2("tls: Unable to set DH parameters. DH cipher suites may not work!");
- WDEBUG2("Fix this by running the OpenSSL command listed in eap.conf");
+ WARN("tls: Unable to set DH parameters. DH cipher suites may not work!");
+ WARN("Fix this by running the OpenSSL command listed in eap.conf");
return 0;
}
* needs to be dynamic so we can supply a "free" function
*/
static int FR_TLS_EX_INDEX_VPS = -1;
+int FR_TLS_EX_INDEX_CERTS = -1;
/*
* Print debugging messages, and free data.
conf->session_cache_path, FR_DIR_SEP, buffer);
rv = unlink(filename);
if (rv != 0) {
- DEBUG2(" SSL: could not remove persisted session file %s: %s", filename, strerror(errno));
+ DEBUG2(" SSL: could not remove persisted session file %s: %s", filename, fr_syserror(errno));
}
/* VPs might be absent; might not have been written to disk yet */
snprintf(filename, sizeof(filename), "%s%c%s.vps",
conf->session_cache_path, FR_DIR_SEP, buffer);
fd = open(filename, O_RDWR|O_CREAT|O_EXCL, 0600);
if (fd < 0) {
- DEBUG2(" SSL: could not open session file %s: %s", filename, strerror(errno));
+ DEBUG2(" SSL: could not open session file %s: %s", filename, fr_syserror(errno));
goto error;
}
while (todo > 0) {
rv = write(fd, p, todo);
if (rv < 1) {
- DEBUG2(" SSL: failed writing session: %s", strerror(errno));
+ DEBUG2(" SSL: failed writing session: %s", fr_syserror(errno));
close(fd);
goto error;
}
size_t size;
char buffer[2 * MAX_SESSION_SIZE + 1];
fr_tls_server_conf_t *conf;
+ TALLOC_CTX *talloc_ctx;
SSL_SESSION *sess = NULL;
unsigned char *sess_data = NULL;
DEBUG2(" SSL: Client requested cached session %s", buffer);
conf = (fr_tls_server_conf_t *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_CONF);
+ talloc_ctx = SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_TALLOC);
if (conf && conf->session_cache_path) {
int rv, fd, todo;
char filename[256];
conf->session_cache_path, FR_DIR_SEP, buffer);
fd = open(filename, O_RDONLY);
if (fd < 0) {
- DEBUG2(" SSL: could not find persisted session file %s: %s", filename, strerror(errno));
+ DEBUG2(" SSL: could not find persisted session file %s: %s", filename, fr_syserror(errno));
goto err;
}
rv = fstat(fd, &st);
if (rv < 0) {
- DEBUG2(" SSL: could not stat persisted session file %s: %s", filename, strerror(errno));
+ DEBUG2(" SSL: could not stat persisted session file %s: %s", filename, fr_syserror(errno));
close(fd);
goto err;
}
while (todo > 0) {
rv = read(fd, p, todo);
if (rv < 1) {
- DEBUG2(" SSL: could not read from persisted session: %s", strerror(errno));
+ DEBUG2(" SSL: could not read from persisted session: %s", fr_syserror(errno));
close(fd);
goto err;
}
}
/* cache the VPs into the session */
- vp = paircopy(NULL, pairlist->reply);
+ vp = paircopy(talloc_ctx, pairlist->reply);
SSL_SESSION_set_ex_data(sess, FR_TLS_EX_INDEX_VPS, vp);
DEBUG2(" SSL: Successfully restored session %s", buffer);
}
*/
/* Get OCSP responder URL */
- if(conf->ocsp_override_url) {
- OCSP_parse_url(conf->ocsp_url, &host, &port, &path, &use_ssl);
+ if (conf->ocsp_override_url) {
+ char *url;
+
+ memcpy(&url, &conf->ocsp_url, sizeof(url));
+ /* Reading the libssl src, they do a strdup on the URL, so it could of been const *sigh* */
+ OCSP_parse_url(url, &host, &port, &path, &use_ssl);
}
else {
ocsp_parse_cert_url(client_cert, &host, &port, &path, &use_ssl);
}
if (!host || !port || !path) {
- DEBUG2("[ocsp] - Host / port / path missing. Not doing OCSP.");
+ DEBUG2("[ocsp] - Host / port / path missing. Not doing OCSP");
ocsp_ok = 2;
goto ocsp_skip;
}
break;
case 2:
if (conf->ocsp_softfail) {
- DEBUG2("[ocsp] --> Unable to check certificate; assuming valid.");
- DEBUG2("[ocsp] --> Warning! This may be insecure.");
+ DEBUG2("[ocsp] --> Unable to check certificate; assuming valid");
+ DEBUG2("[ocsp] --> Warning! This may be insecure");
ocsp_ok = 1;
} else {
DEBUG2("[ocsp] --> Unable to check certificate; failing!");
/*
* For creating certificate attributes.
*/
-static char const *cert_attr_names[6][2] = {
+static char const *cert_attr_names[8][2] = {
{ "TLS-Client-Cert-Serial", "TLS-Cert-Serial" },
{ "TLS-Client-Cert-Expiration", "TLS-Cert-Expiration" },
{ "TLS-Client-Cert-Subject", "TLS-Cert-Subject" },
{ "TLS-Client-Cert-Issuer", "TLS-Cert-Issuer" },
{ "TLS-Client-Cert-Common-Name", "TLS-Cert-Common-Name" },
- { "TLS-Client-Cert-Subject-Alt-Name-Email", "TLS-Cert-Subject-Alt-Name-Email" }
+ { "TLS-Client-Cert-Subject-Alt-Name-Email", "TLS-Cert-Subject-Alt-Name-Email" },
+ { "TLS-Client-Cert-Subject-Alt-Name-Dns", "TLS-Cert-Subject-Alt-Name-Dns" },
+ { "TLS-Client-Cert-Subject-Alt-Name-Upn", "TLS-Cert-Subject-Alt-Name-Upn" }
};
#define FR_TLS_SERIAL (0)
#define FR_TLS_ISSUER (3)
#define FR_TLS_CN (4)
#define FR_TLS_SAN_EMAIL (5)
+#define FR_TLS_SAN_DNS (6)
+#define FR_TLS_SAN_UPN (7)
/*
* Before trusting a certificate, you must make sure that the
X509_STORE *ocsp_store = NULL;
X509 *issuer_cert;
#endif
+ TALLOC_CTX *talloc_ctx;
client_cert = X509_STORE_CTX_get_current_cert(ctx);
err = X509_STORE_CTX_get_error(ctx);
if (!conf) return 1;
request = (REQUEST *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_REQUEST);
-
- if (!request) return 1; /* FIXME: outbound TLS */
-
rad_assert(request != NULL);
certs = (VALUE_PAIR **)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_CERTS);
- rad_assert(certs != NULL);
+
identity = (char **)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_IDENTITY);
#ifdef HAVE_OPENSSL_OCSP_H
ocsp_store = (X509_STORE *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_STORE);
#endif
+ talloc_ctx = SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_TALLOC);
+
/*
* Get the Serial Number
*/
* have a user identity. i.e. we don't create the
* attributes for RadSec connections.
*/
- if (identity &&
+ if (certs && identity &&
(lookup <= 1) && sn && ((size_t) sn->length < (sizeof(buf) / 2))) {
char *p = buf;
int i;
sprintf(p, "%02x", (unsigned int)sn->data[i]);
p += 2;
}
- pairmake(NULL, certs, cert_attr_names[FR_TLS_SERIAL][lookup], buf, T_OP_SET);
+ pairmake(talloc_ctx, certs, cert_attr_names[FR_TLS_SERIAL][lookup], buf, T_OP_SET);
}
*/
buf[0] = '\0';
asn_time = X509_get_notAfter(client_cert);
- if (identity && (lookup <= 1) && asn_time &&
+ if (certs && identity && (lookup <= 1) && asn_time &&
(asn_time->length < (int) sizeof(buf))) {
memcpy(buf, (char*) asn_time->data, asn_time->length);
buf[asn_time->length] = '\0';
- pairmake(NULL, certs, cert_attr_names[FR_TLS_EXPIRATION][lookup], buf, T_OP_SET);
+ pairmake(talloc_ctx, certs, cert_attr_names[FR_TLS_EXPIRATION][lookup], buf, T_OP_SET);
}
/*
X509_NAME_oneline(X509_get_subject_name(client_cert), subject,
sizeof(subject));
subject[sizeof(subject) - 1] = '\0';
- if (identity && (lookup <= 1) && subject[0]) {
- pairmake(NULL, certs, cert_attr_names[FR_TLS_SUBJECT][lookup], subject, T_OP_SET);
+ if (certs && identity && (lookup <= 1) && subject[0]) {
+ pairmake(talloc_ctx, certs, cert_attr_names[FR_TLS_SUBJECT][lookup], subject, T_OP_SET);
}
X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), issuer,
sizeof(issuer));
issuer[sizeof(issuer) - 1] = '\0';
- if (identity && (lookup <= 1) && issuer[0]) {
- pairmake(NULL, certs, cert_attr_names[FR_TLS_ISSUER][lookup], issuer, T_OP_SET);
+ if (certs && identity && (lookup <= 1) && issuer[0]) {
+ pairmake(talloc_ctx, certs, cert_attr_names[FR_TLS_ISSUER][lookup], issuer, T_OP_SET);
}
/*
X509_NAME_get_text_by_NID(X509_get_subject_name(client_cert),
NID_commonName, common_name, sizeof(common_name));
common_name[sizeof(common_name) - 1] = '\0';
- if (identity && (lookup <= 1) && common_name[0] && subject[0]) {
- pairmake(NULL, certs, cert_attr_names[FR_TLS_CN][lookup], common_name, T_OP_SET);
+ if (certs && identity && (lookup <= 1) && common_name[0] && subject[0]) {
+ pairmake(talloc_ctx, certs, cert_attr_names[FR_TLS_CN][lookup], common_name, T_OP_SET);
}
-#ifdef GEN_EMAIL
/*
* Get the RFC822 Subject Alternative Name
*/
loc = X509_get_ext_by_NID(client_cert, NID_subject_alt_name, 0);
- if (lookup <= 1 && loc >= 0) {
+ if (certs && (lookup <= 1) && (loc >= 0)) {
X509_EXTENSION *ext = NULL;
GENERAL_NAMES *names = NULL;
int i;
GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);
switch (name->type) {
+#ifdef GEN_EMAIL
case GEN_EMAIL:
- pairmake(NULL, certs, cert_attr_names[FR_TLS_SAN_EMAIL][lookup],
+ pairmake(talloc_ctx, certs, cert_attr_names[FR_TLS_SAN_EMAIL][lookup],
(char *) ASN1_STRING_data(name->d.rfc822Name), T_OP_SET);
break;
+#endif /* GEN_EMAIL */
+#ifdef GEN_DNS
+ case GEN_DNS:
+ pairmake(talloc_ctx, certs, cert_attr_names[FR_TLS_SAN_DNS][lookup],
+ (char *) ASN1_STRING_data(name->d.dNSName), T_OP_SET);
+ break;
+#endif /* GEN_DNS */
+#ifdef GEN_OTHERNAME
+ case GEN_OTHERNAME:
+ /* look for a MS UPN */
+ if (NID_ms_upn == OBJ_obj2nid(name->d.otherName->type_id)) {
+ /* we've got a UPN - Must be ASN1-encoded UTF8 string */
+ if (name->d.otherName->value->type == V_ASN1_UTF8STRING) {
+ pairmake(talloc_ctx, certs, cert_attr_names[FR_TLS_SAN_UPN][lookup],
+ (char *) ASN1_STRING_data(name->d.otherName->value->value.utf8string), T_OP_SET);
+ break;
+ } else {
+ RWARN("Invalid UPN in Subject Alt Name (should be UTF-8)\n");
+ break;
+ }
+ }
+ break;
+#endif /* GEN_OTHERNAME */
default:
/* XXX TODO handle other SAN types */
break;
if (names != NULL)
sk_GENERAL_NAME_free(names);
}
-#endif /* GEN_EMAIL */
/*
* If the CRL has expired, that might still be OK.
if (*p == ' ') *p = '-';
}
- vp = pairmake(NULL, certs, attribute, value, T_OP_ADD);
+ vp = pairmake(talloc_ctx, certs, attribute, value, T_OP_ADD);
if (vp) debug_pair_list(vp);
}
fd = mkstemp(filename);
if (fd < 0) {
RDEBUG("Failed creating file in %s: %s",
- conf->verify_tmp_dir, strerror(errno));
+ conf->verify_tmp_dir, fr_syserror(errno));
break;
}
fp = fdopen(fd, "w");
if (!fp) {
+ close(fd);
RDEBUG("Failed opening file %s: %s",
- filename, strerror(errno));
+ filename, fr_syserror(errno));
break;
}
VALUE_PAIR *vp = data_ptr;
if (!vp) return;
- DEBUG2(" Freeing cached session VPs %p", vp);
+ DEBUG2(" Freeing cached session VPs");;
pairfree(&vp);
}
-/*
- * Add all the default ciphers and message digests
- * Create our context.
+static void sess_free_certs(UNUSED void *parent, void *data_ptr,
+ UNUSED CRYPTO_EX_DATA *ad, UNUSED int idx,
+ UNUSED long argl, UNUSED void *argp)
+{
+ VALUE_PAIR **certs = data_ptr;
+ if (!certs) return;
+
+ DEBUG2(" Freeing cached session Certificates");
+
+ pairfree(certs);
+}
+
+/** Add all the default ciphers and message digests reate our context.
*
- * This should be called exactly once from main.
+ * This should be called exactly once from main, before reading the main config
+ * or initialising any modules.
*/
void tls_global_init(void)
{
- SSL_library_init();
- SSL_load_error_strings();
+ SSL_load_error_strings(); /* readable error messages (examples show call before library_init) */
+ SSL_library_init(); /* initialize library */
+ OpenSSL_add_all_algorithms(); /* required for SHA2 in OpenSSL < 0.9.8o and 1.0.0.a */
+ OPENSSL_config(NULL);
+}
+
+/** Check for vulnerable versions of libssl
+ *
+ * @param acknowledged The highest CVE number a user has confirmed is not present in the system's libssl.
+ * @return 0 if the CVE specified by the user matches the most recent CVE we have, else -1.
+ */
+int tls_global_version_check(char const *acknowledged)
+{
+ uint64_t v;
+
+ if ((strcmp(acknowledged, libssl_defects[0].id) != 0) && (strcmp(acknowledged, "yes") != 0)) {
+ bool bad = false;
+ size_t i;
+
+ /* Check for bad versions */
+ v = (uint64_t) SSLeay();
+
+ for (i = 0; i < (sizeof(libssl_defects) / sizeof(*libssl_defects)); i++) {
+ libssl_defect_t *defect = &libssl_defects[i];
+
+ if ((v >= defect->low) && (v <= defect->high)) {
+ ERROR("Refusing to start with libssl version %s (in range %s)",
+ ssl_version(), ssl_version_range(defect->low, defect->high));
+ ERROR("Security advisory %s (%s)", defect->id, defect->name);
+ ERROR("%s", defect->comment);
+
+ bad = true;
+ }
+ }
+
+ if (bad) {
+ INFO("Once you have verified libssl has been correctly patched, "
+ "set security.allow_vulnerable_openssl = '%s'", libssl_defects[0].id);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/** Free any memory alloced by libssl
+ *
+ */
+void tls_global_cleanup(void)
+{
+ ERR_remove_state(0);
+ ENGINE_cleanup();
+ CONF_modules_unload(1);
+ ERR_free_strings();
+ EVP_cleanup();
+ CRYPTO_cleanup_all_ex_data();
}
/*
#endif
ctx = SSL_CTX_new(TLSv1_method());
+ if (!ctx) {
+ int err;
+ while ((err = ERR_get_error())) {
+ DEBUG("Failed creating SSL context: %s",
+ ERR_error_string(err, NULL));
+ return NULL;
+ }
+ }
/*
* Save the config on the context so that callbacks which
* programmatically.
*/
char const* special_string = "Apple:UseCertAdmin";
- if (strncmp(conf->private_key_password,
- special_string,
- strlen(special_string)) == 0)
- {
+ if (strncmp(conf->private_key_password, special_string, strlen(special_string)) == 0) {
char cmd[256];
+ char *password;
long const max_password_len = 128;
- snprintf(cmd, sizeof(cmd) - 1,
- "/usr/sbin/certadmin --get-private-key-passphrase \"%s\"",
- conf->private_key_file);
+ snprintf(cmd, sizeof(cmd) - 1, "/usr/sbin/certadmin --get-private-key-passphrase \"%s\"",
+ conf->private_key_file);
DEBUG2("tls: Getting private key passphrase using command \"%s\"", cmd);
return NULL;
}
- talloc_free(conf->private_key_password);
- conf->private_key_password = talloc_array(conf, char, max_password_len);
- if (!conf->private_key_password) {
+ rad_const_free(conf->private_key_password);
+ password = talloc_array(conf, char, max_password_len);
+ if (!password) {
ERROR("TLS: Can't allocate space for private_key_password");
ERROR("TLS: Error reading private_key_file %s", conf->private_key_file);
pclose(cmd_pipe);
return NULL;
}
- fgets(conf->private_key_password, max_password_len, cmd_pipe);
+ fgets(password, max_password_len, cmd_pipe);
pclose(cmd_pipe);
/* Get rid of newline at end of password. */
- conf->private_key_password[strlen(conf->private_key_password) - 1] = '\0';
- DEBUG2("tls: Password from command = \"%s\"", conf->private_key_password);
+ password[strlen(password) - 1] = '\0';
+
+ DEBUG3("tls: Password from command = \"%s\"", password);
+ conf->private_key_password = password;
}
#endif
- SSL_CTX_set_default_passwd_cb_userdata(ctx, conf->private_key_password);
- SSL_CTX_set_default_passwd_cb(ctx, cbtls_password);
+
+ {
+ char *password;
+
+ memcpy(&password, &conf->private_key_password, sizeof(password));
+ SSL_CTX_set_default_passwd_cb_userdata(ctx, password);
+ SSL_CTX_set_default_passwd_cb(ctx, cbtls_password);
+ }
}
#ifdef PSK_MAX_IDENTITY_LEN
SSL_CTX_set_quiet_shutdown(ctx, 1);
if (FR_TLS_EX_INDEX_VPS < 0)
FR_TLS_EX_INDEX_VPS = SSL_SESSION_get_ex_new_index(0, NULL, NULL, NULL, sess_free_vps);
+ if (FR_TLS_EX_INDEX_CERTS < 0)
+ FR_TLS_EX_INDEX_CERTS = SSL_SESSION_get_ex_new_index(0, NULL, NULL, NULL, sess_free_certs);
}
/*
/* Load randomness */
if (conf->random_file) {
- if (!(RAND_load_file(conf->random_file, 1024*1024))) {
+ if (!(RAND_load_file(conf->random_file, 1024*10))) {
ERROR("tls: SSL error %s", ERR_error_string(ERR_get_error(), NULL));
ERROR("tls: Error loading randomness");
return NULL;
* added to automatically free the data when the CONF_SECTION
* is freed.
*/
-static void tls_server_conf_free(fr_tls_server_conf_t *conf)
+static int tls_server_conf_free(fr_tls_server_conf_t *conf)
{
- if (!conf) return;
-
if (conf->ctx) SSL_CTX_free(conf->ctx);
#ifdef HAVE_OPENSSL_OCSP_H
#ifndef NDEBUG
memset(conf, 0, sizeof(*conf));
#endif
- talloc_free(conf);
+ return 0;
}
return NULL;
}
+ talloc_set_destructor(conf, tls_server_conf_free);
+
if (cf_section_parse(cs, conf, tls_server_config) < 0) {
error:
- tls_server_conf_free(conf);
+ talloc_free(conf);
return NULL;
}
if (conf->ocsp_store == NULL) goto error;
}
#endif /*HAVE_OPENSSL_OCSP_H*/
+ {
+ char *dh_file;
- if (load_dh_params(conf->ctx, conf->dh_file) < 0) {
- goto error;
+ memcpy(&dh_file, &conf->dh_file, sizeof(dh_file));
+ if (load_dh_params(conf->ctx, dh_file) < 0) {
+ goto error;
+ }
}
if (generate_eph_rsa_key(conf->ctx) < 0) {
if (conf->verify_tmp_dir) {
if (chmod(conf->verify_tmp_dir, S_IRWXU) < 0) {
- ERROR("Failed changing permissions on %s: %s", conf->verify_tmp_dir, strerror(errno));
+ ERROR("Failed changing permissions on %s: %s", conf->verify_tmp_dir, fr_syserror(errno));
goto error;
}
}
/*
* Cache conf in cs in case we're asked to parse this again.
*/
- cf_data_add(cs, "tls-conf", conf, (void *)(void *) tls_server_conf_free);
+ cf_data_add(cs, "tls-conf", conf, NULL);
return conf;
}
return NULL;
}
+ talloc_set_destructor(conf, tls_server_conf_free);
+
if (cf_section_parse(cs, conf, tls_client_config) < 0) {
error:
- tls_server_conf_free(conf);
+ talloc_free(conf);
return NULL;
}
goto error;
}
- if (load_dh_params(conf->ctx, conf->dh_file) < 0) {
- goto error;
+ {
+ char *dh_file;
+
+ memcpy(&dh_file, &conf->dh_file, sizeof(dh_file));
+ if (load_dh_params(conf->ctx, dh_file) < 0) {
+ goto error;
+ }
}
if (generate_eph_rsa_key(conf->ctx) < 0) {
goto error;
}
- cf_data_add(cs, "tls-conf", conf, (void *)(void *) tls_server_conf_free);
+ cf_data_add(cs, "tls-conf", conf, NULL);
return conf;
}
{
VALUE_PAIR *vp, *vps = NULL;
fr_tls_server_conf_t *conf;
+ TALLOC_CTX *talloc_ctx;
conf = (fr_tls_server_conf_t *)SSL_get_ex_data(ssn->ssl, FR_TLS_EX_INDEX_CONF);
rad_assert(conf != NULL);
+ talloc_ctx = SSL_get_ex_data(ssn->ssl, FR_TLS_EX_INDEX_TALLOC);
+
/*
* If there's no session resumption, delete the entry
* from the cache. This means either it's disabled
* not allowed,
*/
if (SSL_session_reused(ssn->ssl)) {
- RDEBUG("FAIL: Forcibly stopping session resumption as it is not allowed.");
+ RDEBUG("FAIL: Forcibly stopping session resumption as it is not allowed");
return -1;
}
fr_bin2hex(buffer, ssn->ssl->session->session_id, size);
- vp = paircopy2(NULL, request->reply->vps, PW_USER_NAME, 0, TAG_ANY);
+ vp = paircopy2(talloc_ctx, request->reply->vps, PW_USER_NAME, 0, TAG_ANY);
+ if (vp) pairadd(&vps, vp);
+
+ vp = paircopy2(talloc_ctx, request->packet->vps, PW_STRIPPED_USER_NAME, 0, TAG_ANY);
if (vp) pairadd(&vps, vp);
- vp = paircopy2(NULL, request->packet->vps, PW_STRIPPED_USER_NAME, 0, TAG_ANY);
+ vp = paircopy2(talloc_ctx, request->reply->vps, PW_CHARGEABLE_USER_IDENTITY, 0, TAG_ANY);
if (vp) pairadd(&vps, vp);
- vp = paircopy2(NULL, request->reply->vps, PW_CACHED_SESSION_POLICY, 0, TAG_ANY);
+ vp = paircopy2(talloc_ctx, request->reply->vps, PW_CACHED_SESSION_POLICY, 0, TAG_ANY);
if (vp) pairadd(&vps, vp);
certs = (VALUE_PAIR **)SSL_get_ex_data(ssn->ssl, FR_TLS_EX_INDEX_CERTS);
* @todo: some go into reply, others into
* request
*/
- pairadd(&vps, paircopy(NULL, *certs));
+ pairadd(&vps, paircopy(talloc_ctx, *certs));
}
if (vps) {
);
vp_file = fopen(filename, "w");
if (vp_file == NULL) {
- RDEBUG2("Could not write session VPs to persistent cache: %s", strerror(errno));
+ RDEBUG2("Could not write session VPs to persistent cache: %s", fr_syserror(errno));
} else {
vp_cursor_t cursor;
/* generate a dummy user-style entry which is easy to read back */
fprintf(vp_file, "# SSL cached session\n");
fprintf(vp_file, "%s\n", buffer);
- for (vp = paircursor(&cursor, &vps);
+ for (vp = fr_cursor_init(&cursor, &vps);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
vp_prints(buf, sizeof(buf), vp);
- fprintf(vp_file, "\t%s%s\n", buf, ",");
+ fprintf(vp_file, "\t%s,\n", buf);
}
fclose(vp_file);
}
RDEBUG("Adding cached attributes for session %s:", buffer);
debug_pair_list(vps);
- for (vp = paircursor(&cursor, &vps);
+ for (vp = fr_cursor_init(&cursor, &vps);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
/*
* TLS-* attrs get added back to
* the request list.
break;
default:
- DEBUG("Error in fragmentation logic: ?");
+ DEBUG("Error in fragmentation logic: %s",
+ ERR_error_string(code, NULL));
/*
* FIXME: Call int_ssl_check?
}
if (err == 0) {
- RWDEBUG("No data inside of the tunnel.");
+ RWDEBUG("No data inside of the tunnel");
}
/*
RDEBUG2("Received TLS ACK");
if (ssn == NULL){
- RERROR("FAIL: Unexpected ACK received. Could not obtain session information.");
+ RERROR("FAIL: Unexpected ACK received. Could not obtain session information");
return FR_TLS_INVALID;
}
if (ssn->info.initialized == 0) {
- RDEBUG("No SSL info available. Waiting for more SSL data.");
+ RDEBUG("No SSL info available. Waiting for more SSL data");
return FR_TLS_REQUEST;
}
if ((ssn->info.content_type == handshake) &&
(ssn->info.origin == 0)) {
- RERROR("FAIL: ACK without earlier message.");
+ RERROR("FAIL: ACK without earlier message");
return FR_TLS_INVALID;
}
{
listen_socket_t *sock = listener->data;
+ SSL_shutdown(sock->ssn->ssl);
+
+
listener->status = RAD_LISTEN_STATUS_EOL;
listener->tls = NULL; /* parent owns this! */
- if (sock->parent) {
- /*
- * Decrement the number of connections.
- */
- if (sock->parent->limit.num_connections > 0) {
- sock->parent->limit.num_connections--;
- }
- if (sock->client->limit.num_connections > 0) {
- sock->client->limit.num_connections--;
- }
- }
-
/*
* Tell the event handler that an FD has disappeared.
*/
DEBUG("Client has closed connection");
- event_new_fd(listener);
+ radius_update_listener(listener);
/*
* Do NOT free the listener here. It's in use by
*/
}
-static int tls_socket_write(rad_listen_t *listener, REQUEST *request)
+static int CC_HINT(nonnull) tls_socket_write(rad_listen_t *listener, REQUEST *request)
{
uint8_t *p;
ssize_t rcode;
rcode = write(request->packet->sockfd, p,
(sock->ssn->dirty_out.data + sock->ssn->dirty_out.used) - p);
if (rcode <= 0) {
- RDEBUG("Error writing to TLS socket: %s", strerror(errno));
+ RDEBUG("Error writing to TLS socket: %s", fr_syserror(errno));
tls_socket_close(listener);
return 0;
static int tls_socket_recv(rad_listen_t *listener)
{
- int doing_init = false;
+ bool doing_init = false;
ssize_t rcode;
RADIUS_PACKET *packet;
REQUEST *request;
(void) talloc_steal(sock, sock->ssn);
SSL_set_ex_data(sock->ssn->ssl, FR_TLS_EX_INDEX_REQUEST, (void *)request);
SSL_set_ex_data(sock->ssn->ssl, FR_TLS_EX_INDEX_CERTS, (void *)&request->packet->vps);
+ SSL_set_ex_data(sock->ssn->ssl, FR_TLS_EX_INDEX_TALLOC, sock->parent);
doing_init = true;
}
sizeof(sock->ssn->dirty_in.data));
if ((rcode < 0) && (errno == ECONNRESET)) {
do_close:
- PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+ DEBUG("Closing TLS socket from client port %u", sock->other_port);
tls_socket_close(listener);
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
return 0;
}
if (rcode < 0) {
- RDEBUG("Error reading TLS socket: %s", strerror(errno));
+ RDEBUG("Error reading TLS socket: %s", fr_syserror(errno));
goto do_close;
}
packet->vps = NULL;
PTHREAD_MUTEX_UNLOCK(&sock->mutex);
- if (!rad_packet_ok(packet, 0)) {
+ if (!rad_packet_ok(packet, 0, NULL)) {
RDEBUG("Received bad packet: %s", fr_strerror());
+ DEBUG("Closing TLS socket from client");
+ PTHREAD_MUTEX_LOCK(&sock->mutex);
tls_socket_close(listener);
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
return 0; /* do_close unlocks the mutex */
}
if (fr_debug_flag) {
char host_ipaddr[128];
- if ((packet->code > 0) && (packet->code < FR_MAX_PACKET_CODE)) {
+ if (is_radius_code(packet->code)) {
RDEBUG("tls_recv: %s packet from host %s port %d, id=%d, length=%d",
fr_packet_codes[packet->code],
inet_ntop(packet->src_ipaddr.af,
* set.
*/
switch(packet->code) {
- case PW_AUTHENTICATION_REQUEST:
+ case PW_CODE_AUTHENTICATION_REQUEST:
if (listener->type != RAD_LISTEN_AUTH) goto bad_packet;
FR_STATS_INC(auth, total_requests);
fun = rad_authenticate;
break;
#ifdef WITH_ACCOUNTING
- case PW_ACCOUNTING_REQUEST:
+ case PW_CODE_ACCOUNTING_REQUEST:
if (listener->type != RAD_LISTEN_ACCT) {
/*
* Allow auth + dual. Disallow
break;
#endif
- case PW_STATUS_SERVER:
- if (!mainconfig.status_server) {
+ case PW_CODE_STATUS_SERVER:
+ if (!main_config.status_server) {
FR_STATS_INC(auth, total_unknown_types);
- WDEBUG("Ignoring Status-Server request due to security configuration");
+ WARN("Ignoring Status-Server request due to security configuration");
rad_free(&sock->packet);
request->packet = NULL;
return 0;
{
listen_socket_t *sock = listener->data;
+ VERIFY_REQUEST(request);
+
rad_assert(request->listener == listener);
rad_assert(listener->send == dual_tls_send);
*/
if (rad_encode(request->reply, request->packet,
request->client->secret) < 0) {
- RDEBUG("Failed encoding packet: %s", fr_strerror());
+ RERROR("Failed encoding packet: %s", fr_strerror());
return 0;
}
*/
if (rad_sign(request->reply, request->packet,
request->client->secret) < 0) {
- RDEBUG("Failed signing packet: %s", fr_strerror());
+ RERROR("Failed signing packet: %s", fr_strerror());
return 0;
}
#ifdef WITH_PROXY
-int proxy_tls_recv(rad_listen_t *listener)
+/*
+ * Read from the SSL socket. Safe with either blocking or
+ * non-blocking IO. This level of complexity is probably not
+ * necessary, as each packet gets put into one SSL application
+ * record. When SSL has a full record, we should be able to read
+ * the entire packet via one SSL_read().
+ *
+ * When SSL has a partial record, SSL_read() will return
+ * WANT_READ or WANT_WRITE, and zero application data.
+ *
+ * Called with the mutex held.
+ */
+static ssize_t proxy_tls_read(rad_listen_t *listener)
{
int rcode;
size_t length;
- listen_socket_t *sock = listener->data;
- char buffer[256];
- RADIUS_PACKET *packet;
uint8_t *data;
+ listen_socket_t *sock = listener->data;
/*
* Get the maximum size of data to receive.
*/
if (!sock->data) sock->data = talloc_array(sock, uint8_t,
sock->ssn->offset);
+
data = sock->data;
- if (listener->status != RAD_LISTEN_STATUS_KNOWN) return 0;
- DEBUG3("Proxy SSL socket has data to read");
- PTHREAD_MUTEX_LOCK(&sock->mutex);
-redo:
- rcode = SSL_read(sock->ssn->ssl, data, 4);
- if (rcode <= 0) {
- int err = SSL_get_error(sock->ssn->ssl, rcode);
- switch (err) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- goto redo;
+ if (sock->partial < 4) {
+ rcode = SSL_read(sock->ssn->ssl, data + sock->partial,
+ 4 - sock->partial);
+ if (rcode <= 0) {
+ int err = SSL_get_error(sock->ssn->ssl, rcode);
+ switch (err) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ return 0; /* do some more work later */
+
+ case SSL_ERROR_ZERO_RETURN:
+ /* remote end sent close_notify, send one back */
+ SSL_shutdown(sock->ssn->ssl);
+
+ case SSL_ERROR_SYSCALL:
+ do_close:
+ return -1;
+
+ default:
+ while ((err = ERR_get_error())) {
+ DEBUG("proxy recv says %s",
+ ERR_error_string(err, NULL));
+ }
+
+ goto do_close;
+ }
+ }
- case SSL_ERROR_ZERO_RETURN:
- /* remote end sent close_notify, send one back */
- SSL_shutdown(sock->ssn->ssl);
+ sock->partial = rcode;
+ } /* try reading the packet header */
- case SSL_ERROR_SYSCALL:
- do_close:
- PTHREAD_MUTEX_UNLOCK(&sock->mutex);
- tls_socket_close(listener);
- return 0;
+ if (sock->partial < 4) return 0; /* read more data */
- default:
- while ((err = ERR_get_error())) {
- DEBUG("proxy recv says %s",
- ERR_error_string(err, NULL));
- }
+ length = (data[2] << 8) | data[3];
+
+ /*
+ * Do these checks only once, when we read the header.
+ */
+ if (sock->partial == 4) {
+ DEBUG3("Proxy received header saying we have a packet of %u bytes",
+ (unsigned int) length);
+ /*
+ * FIXME: allocate a RADIUS_PACKET, and set
+ * "data" to be as large as necessary.
+ */
+ if (length > sock->ssn->offset) {
+ INFO("Received packet will be too large! Set \"fragment_size = %u\"",
+ (data[2] << 8) | data[3]);
goto do_close;
}
}
- length = (data[2] << 8) | data[3];
- DEBUG3("Proxy received header saying we have a packet of %u bytes",
- (unsigned int) length);
+ /*
+ * Try to read some more.
+ */
+ if (sock->partial < length) {
+ rcode = SSL_read(sock->ssn->ssl, data + sock->partial,
+ length - sock->partial);
+ if (rcode <= 0) {
+ switch (SSL_get_error(sock->ssn->ssl, rcode)) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ return 0;
+
+ case SSL_ERROR_ZERO_RETURN:
+ /* remote end sent close_notify, send one back */
+ SSL_shutdown(sock->ssn->ssl);
+ goto do_close;
+ default:
+ goto do_close;
+ }
+ }
- if (length > sock->ssn->offset) {
- INFO("Received packet will be too large! Set \"fragment_size=%u\"",
- (data[2] << 8) | data[3]);
- goto do_close;
+ sock->partial += rcode;
}
- rcode = SSL_read(sock->ssn->ssl, data + 4, length);
- if (rcode <= 0) {
- switch (SSL_get_error(sock->ssn->ssl, rcode)) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- break;
+ /*
+ * If we're not done, say so.
+ *
+ * Otherwise, reset the partially read data flag, and say
+ * we have a packet.
+ */
+ if (sock->partial < length) {
+ return 0;
+ }
+ sock->partial = 0; /* we've now read the packet */
+ return length;
+}
- case SSL_ERROR_ZERO_RETURN:
- /* remote end sent close_notify, send one back */
- SSL_shutdown(sock->ssn->ssl);
- goto do_close;
- default:
- goto do_close;
- }
+int proxy_tls_recv(rad_listen_t *listener)
+{
+ listen_socket_t *sock = listener->data;
+ char buffer[256];
+ RADIUS_PACKET *packet;
+ uint8_t *data;
+ ssize_t data_len;
+
+ if (listener->status != RAD_LISTEN_STATUS_KNOWN) return 0;
- }
+ DEBUG3("Proxy SSL socket has data to read");
+ PTHREAD_MUTEX_LOCK(&sock->mutex);
+ data_len = proxy_tls_read(listener);
PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+ if (data_len < 0) {
+ DEBUG("Closing TLS socket to home server");
+ PTHREAD_MUTEX_LOCK(&sock->mutex);
+ tls_socket_close(listener);
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+ return 0;
+ }
+
+ if (data_len == 0) return 0; /* not done yet */
+
+ data = sock->data;
+
packet = rad_alloc(sock, 0);
packet->sockfd = listener->fd;
packet->src_ipaddr = sock->other_ipaddr;
packet->dst_port = sock->my_port;
packet->code = data[0];
packet->id = data[1];
- packet->data_len = length;
+ packet->data_len = data_len;
packet->data = talloc_array(packet, uint8_t, packet->data_len);
memcpy(packet->data, data, packet->data_len);
memcpy(packet->vector, packet->data + 4, 16);
* FIXME: Client MIB updates?
*/
switch(packet->code) {
- case PW_AUTHENTICATION_ACK:
- case PW_ACCESS_CHALLENGE:
- case PW_AUTHENTICATION_REJECT:
+ case PW_CODE_AUTHENTICATION_ACK:
+ case PW_CODE_ACCESS_CHALLENGE:
+ case PW_CODE_AUTHENTICATION_REJECT:
break;
#ifdef WITH_ACCOUNTING
- case PW_ACCOUNTING_RESPONSE:
+ case PW_CODE_ACCOUNTING_RESPONSE:
break;
#endif
return 1;
}
+
int proxy_tls_send(rad_listen_t *listener, REQUEST *request)
{
int rcode;
listen_socket_t *sock = listener->data;
- if (listener->status != RAD_LISTEN_STATUS_KNOWN) return 0;
+ VERIFY_REQUEST(request);
+
+ if ((listener->status != RAD_LISTEN_STATUS_INIT) &&
+ (listener->status != RAD_LISTEN_STATUS_KNOWN)) return 0;
/*
* Normal proxying calls us with the data already
DEBUG3("Proxy is writing %u bytes to SSL",
(unsigned int) request->proxy->data_len);
PTHREAD_MUTEX_LOCK(&sock->mutex);
- while ((rcode = SSL_write(sock->ssn->ssl, request->proxy->data,
- request->proxy->data_len)) < 0) {
+ rcode = SSL_write(sock->ssn->ssl, request->proxy->data,
+ request->proxy->data_len);
+ if (rcode < 0) {
int err;
- while ((err = ERR_get_error())) {
+
+ err = ERR_get_error();
+ switch (err) {
+ case SSL_ERROR_NONE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ break; /* let someone else retry */
+
+ default:
DEBUG("proxy SSL_write says %s",
ERR_error_string(err, NULL));
+ DEBUG("Closing TLS socket to home server");
+ tls_socket_close(listener);
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+ return 0;
}
- PTHREAD_MUTEX_UNLOCK(&sock->mutex);
- tls_socket_close(listener);
- return 0;
}
PTHREAD_MUTEX_UNLOCK(&sock->mutex);
bool check_config = false;
bool log_stripped_names = false;
-int filedone = 0;
+bool filedone = false;
char const *radiusd_version = "FreeRADIUS Version " RADIUSD_VERSION_STRING
#ifdef RADIUSD_VERSION_COMMIT
-" (git #" RADIUSD_VERSION_COMMIT ")"
+" (git #" STRINGIFY(RADIUSD_VERSION_COMMIT) ")"
#endif
", for host " HOSTINFO ", built on " __DATE__ " at " __TIME__;
*/
static void usage(int);
-#ifdef WITH_VERIFY_PTR
-static void die_horribly(char const *reason)
-{
- ERROR("talloc abort: %s\n", reason);
- abort();
-}
-#endif
-
void listen_free(UNUSED rad_listen_t **head)
{
/* do nothing */
request->number = 0;
request->master_state = REQUEST_ACTIVE;
- request->child_state = REQUEST_ACTIVE;
+ request->child_state = REQUEST_RUNNING;
request->handle = NULL;
- request->server = talloc_strdup(request, "default");
+ request->server = talloc_typed_strdup(request, "default");
- request->root = &mainconfig;
+ request->root = &main_config;
/*
* Read packet from fp
*/
- request->packet->vps = readvp2(request->packet, fp, &filedone, "radiusd:");
- if (!request->packet->vps) {
+ if (readvp2(&request->packet->vps, request->packet, fp, &filedone) < 0) {
+ fr_perror("unittest");
talloc_free(request);
return NULL;
}
/*
* Set the defaults for IPs, etc.
*/
- request->packet->code = PW_AUTHENTICATION_REQUEST;
+ request->packet->code = PW_CODE_AUTHENTICATION_REQUEST;
request->packet->src_ipaddr.af = AF_INET;
request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_LOOPBACK);
*
* Fix up Digest-Attributes issues
*/
- for (vp = paircursor(&cursor, &request->packet->vps);
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
/*
* Double quoted strings get marked up as xlat expansions,
* but we don't support that here.
/* overlapping! */
{
DICT_ATTR const *da;
- uint8_t *p;
+ uint8_t *p, *q;
p = talloc_array(vp, uint8_t, vp->length + 2);
vp->length += 2;
p[1] = vp->length;
- pairmemsteal(vp, p);
-
da = dict_attrbyvalue(PW_DIGEST_ATTRIBUTES, 0);
rad_assert(da != NULL);
vp->da = da;
+
+ /*
+ * Re-do pairmemsteal ourselves,
+ * because we play games with
+ * vp->da, and pairmemsteal goes
+ * to GREAT lengths to sanitize
+ * and fix and change and
+ * double-check the various
+ * fields.
+ */
+ memcpy(&q, &vp->vp_octets, sizeof(q));
+ talloc_free(q);
+
+ vp->vp_octets = talloc_steal(vp, p);
+ vp->type = VT_DATA;
+
+ VERIFY_VP(vp);
}
break;
} /* loop over the VP's we read in */
if (debug_flag) {
- for (vp = paircursor(&cursor, &request->packet->vps);
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
/*
* Take this opportunity to verify all the VALUE_PAIRs are still valid.
*/
if (!talloc_get_type(vp, VALUE_PAIR)) {
ERROR("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp));
-
- log_talloc_report(vp);
+
+ fr_log_talloc_report(vp);
rad_assert(0);
}
-
+
vp_print(fr_log_fp, vp);
}
fflush(fr_log_fp);
/*
* Debugging
*/
- request->options = debug_flag;
- request->radlog = radlog_request;
+ request->log.lvl = debug_flag;
+ request->log.func = vradlog_request;
request->username = pairfind(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
request->password = pairfind(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
fprintf(fp, "%s\n", fr_packet_codes[packet->code]);
- for (vp = paircursor(&cursor, &packet->vps);
+ for (vp = fr_cursor_init(&cursor, &packet->vps);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
/*
* Take this opportunity to verify all the VALUE_PAIRs are still valid.
*/
if (!talloc_get_type(vp, VALUE_PAIR)) {
ERROR("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp));
- log_talloc_report(vp);
+ fr_log_talloc_report(vp);
rad_assert(0);
}
const char *output_file = NULL;
const char *filter_file = NULL;
FILE *fp;
- REQUEST *request;
+ REQUEST *request = NULL;
VALUE_PAIR *vp;
VALUE_PAIR *filter_vps = NULL;
+ /*
+ * 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("unittest");
+ exit(EXIT_FAILURE);
+ }
+#endif
+
if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL)
progname = argv[0];
else
progname++;
debug_flag = 0;
- radius_dir = talloc_strdup(NULL, RADIUS_DIR);
+ set_radius_dir(NULL, RADIUS_DIR);
/*
* Ensure that the configuration is initialized.
*/
- memset(&mainconfig, 0, sizeof(mainconfig));
- mainconfig.myip.af = AF_UNSPEC;
- mainconfig.port = -1;
- mainconfig.name = "radiusd";
+ memset(&main_config, 0, sizeof(main_config));
+ main_config.myip.af = AF_UNSPEC;
+ main_config.port = 0;
+ main_config.name = "radiusd";
/*
* The tests should have only IPs, not host names.
* We always log to stdout.
*/
fr_log_fp = stdout;
- default_log.dest = L_DST_STDOUT;
+ default_log.dst = L_DST_STDOUT;
default_log.fd = STDOUT_FILENO;
/* Process the options. */
switch(argval) {
case 'd':
- if (radius_dir) {
- rad_const_free(radius_dir);
- }
- radius_dir = talloc_strdup(NULL, optarg);
+ set_radius_dir(NULL, optarg);
break;
case 'D':
- mainconfig.dictionary_dir = talloc_strdup(NULL, optarg);
+ main_config.dictionary_dir = talloc_typed_strdup(NULL, optarg);
break;
case 'f':
break;
case 'm':
- mainconfig.debug_memory = 1;
+ main_config.debug_memory = true;
break;
case 'M':
- memory_report = 1;
- mainconfig.debug_memory = 1;
+ memory_report = true;
+ main_config.debug_memory = true;
break;
case 'n':
- mainconfig.name = optarg;
+ main_config.name = optarg;
break;
case 'o':
case 'X':
debug_flag += 2;
- mainconfig.log_auth = true;
- mainconfig.log_auth_badpass = true;
- mainconfig.log_auth_goodpass = true;
+ main_config.log_auth = true;
+ main_config.log_auth_badpass = true;
+ main_config.log_auth_goodpass = true;
break;
case 'x':
}
}
- if (memory_report) {
- talloc_enable_null_tracking();
-#ifdef WITH_VERIFY_PTR
- talloc_set_abort_fn(die_horribly);
-#endif
- }
- talloc_set_log_fn(log_talloc);
-
if (debug_flag) {
version();
}
fr_debug_flag = debug_flag;
- /* Read the configuration files, BEFORE doing anything else. */
- if (read_mainconfig(0) < 0) {
+ /*
+ * Mismatch between the binary and the libraries it depends on
+ */
+ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
+ fr_perror("radiusd");
exit(EXIT_FAILURE);
}
+ /* Read the configuration files, BEFORE doing anything else. */
+ if (main_config_init() < 0) {
+ rcode = EXIT_FAILURE;
+ goto finish;
+ }
+
+ /*
+ * Load the modules
+ */
+ if (modules_init(main_config.config) < 0) {
+ rcode = EXIT_FAILURE;
+ goto finish;
+ }
+
+ /* Set the panic action (if required) */
+ if (main_config.panic_action &&
+#ifndef NDEBUG
+ !getenv("PANIC_ACTION") &&
+#endif
+ (fr_fault_setup(main_config.panic_action, argv[0]) < 0)) {
+ rcode = EXIT_FAILURE;
+ goto finish;
+ }
+
setlinebuf(stdout); /* unbuffered output */
if (!input_file || (strcmp(input_file, "-") == 0)) {
fp = fopen(input_file, "r");
if (!fp) {
fprintf(stderr, "Failed reading %s: %s\n",
- input_file, strerror(errno));
- exit(EXIT_FAILURE);
+ input_file, fr_syserror(errno));
+ goto finish;
}
}
request = request_setup(fp);
if (!request) {
fprintf(stderr, "Failed reading input: %s\n", fr_strerror());
- exit(EXIT_FAILURE);
+ rcode = EXIT_FAILURE;
+ goto finish;
}
/*
fclose(fp);
fp = NULL;
}
- filedone = 0;
+ filedone = false;
}
/*
if (!fp) {
fp = fopen(filter_file, "r");
if (!fp) {
- fprintf(stderr, "Failed reading %s: %s\n",
- filter_file, strerror(errno));
- exit(EXIT_FAILURE);
+ fprintf(stderr, "Failed reading %s: %s\n", filter_file, strerror(errno));
+ rcode = EXIT_FAILURE;
+ goto finish;
}
}
- filter_vps = readvp2(request, fp, &filedone, "radiusd");
- if (!filter_vps) {
+
+ if (readvp2(&filter_vps, request, fp, &filedone) < 0) {
fprintf(stderr, "Failed reading attributes from %s: %s\n",
filter_file, fr_strerror());
- exit(EXIT_FAILURE);
+ rcode = EXIT_FAILURE;
+ goto finish;
}
/*
fp = fopen(output_file, "w");
if (!fp) {
fprintf(stderr, "Failed writing %s: %s\n",
- output_file, strerror(errno));
+ output_file, fr_syserror(errno));
exit(EXIT_FAILURE);
}
}
/*
* Update the list with the response type.
*/
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
PW_RESPONSE_PACKET_TYPE, 0);
vp->vp_integer = request->reply->code;
- if (filter_vps && !pairvalidate(filter_vps, request->reply->vps)) {
- fprintf(stderr, "Output file %s does not match attributes in filter %s\n",
- output_file ? output_file : input_file, filter_file);
- exit(EXIT_FAILURE);
+ {
+ VALUE_PAIR const *failed[2];
+
+ if (filter_vps && !pairvalidate(failed, filter_vps, request->reply->vps)) {
+ pairvalidate_debug(request, failed);
+ fr_perror("Output file %s does not match attributes in filter %s",
+ output_file ? output_file : input_file, filter_file);
+ rcode = EXIT_FAILURE;
+ goto finish;
+ }
}
- talloc_free(request);
+ INFO("Exiting normally");
- INFO("Exiting normally.");
+finish:
+ talloc_free(request);
/*
* Detach any modules.
*/
- detach_modules();
+ modules_free();
xlat_free(); /* modules may have xlat's */
/*
* Free the configuration items.
*/
- free_mainconfig();
-
- rad_const_free(radius_dir);
+ main_config_free();
if (memory_report) {
INFO("Allocated memory at time of report:");
- log_talloc_report(NULL);
+ fr_log_talloc_report(NULL);
}
return rcode;
#include <freeradius-devel/rad_assert.h>
#include <ctype.h>
-#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
}
/*
- * Check a filename for sanity.
- *
- * Allow only uppercase/lowercase letters, numbers, and '-_/.'
- */
-int rad_checkfilename(char const *filename)
-{
- if (strspn(filename, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_/.") == strlen(filename)) {
- return 0;
- }
-
- return -1;
-}
-
-/** Check if file exists
- *
- * @param filename to check.
- * @return 0 if the file does not exist, 1 if the file exists, -1 if the file
- * exists but there was an error opening it. errno value should be usable
- * for error messages.
- */
-int rad_file_exists(char const *filename)
-{
- int des;
- int ret = 1;
-
- if ((des = open(filename, O_RDONLY)) == -1) {
- if (errno == ENOENT) {
- ret = 0;
- } else {
- ret = -1;
- }
- } else {
- close(des);
- }
-
- return ret;
-}
-
-/*
* Create possibly many directories.
*
* Note that the input directory name is NOT a constant!
{
int rcode;
char *p;
- struct stat st;
-
- /*
- * If the directory exists, don't do anything.
- */
- if (stat(directory, &st) == 0) {
- return 0;
- }
/*
- * Look for the LAST directory name. Try to create that,
- * failing on any error.
+ * Try to make the directory. If it exists, chmod it.
+ * If a path doesn't exist, that's OK. Otherwise
+ * return with an error.
*/
- p = strrchr(directory, FR_DIR_SEP);
- if (p != NULL) {
- *p = '\0';
- rcode = rad_mkdir(directory, mode);
+ rcode = mkdir(directory, mode & 0777);
+ if (rcode < 0) {
+ if (errno == EEXIST) {
+ return chmod(directory, mode);
+ }
- /*
- * On error, we leave the directory name as the
- * one which caused the error.
- */
- if (rcode < 0) {
- if (errno == EEXIST) return 0;
+ if (errno != ENOENT) {
return rcode;
}
/*
- * Reset the directory delimiter, and go ask
- * the system to make the directory.
+ * A component in the directory path doesn't
+ * exist. Look for the LAST directory name. Try
+ * to create that. If there's an error, we leave
+ * the directory path as the one at which the
+ * error occured.
*/
- *p = FR_DIR_SEP;
- } else {
- return 0;
- }
+ p = strrchr(directory, FR_DIR_SEP);
+ if (!p || (p == directory)) return -1;
- /*
- * Having done everything successfully, we do the
- * system call to actually go create the directory.
- */
- rcode = mkdir(directory, mode & 0777);
- if (rcode < 0) {
- return rcode;
- }
+ *p = '\0';
+ rcode = rad_mkdir(directory, mode);
+ if (rcode < 0) return rcode;
- /*
- * Set things like sticky bits that aren't supported by
- * mkdir.
- */
- if (mode & ~0777) {
- rcode = chmod(directory, mode);
- }
+ /*
+ * Reset the directory path, and try again to
+ * make the directory.
+ */
+ *p = FR_DIR_SEP;
+ rcode = mkdir(directory, mode & 0777);
+ if (rcode < 0) return rcode;
+ } /* else we successfully created the directory */
- return rcode;
+ return chmod(directory, mode);
}
}
-void *rad_calloc(size_t size)
-{
- void *ptr = rad_malloc(size);
- memset(ptr, 0, size);
- return ptr;
-}
-
void rad_const_free(void const *ptr)
{
void *tmp;
*
*/
-void NEVER_RETURNS rad_assert_fail (char const *file, unsigned int line,
- char const *expr)
+void NEVER_RETURNS rad_assert_fail(char const *file, unsigned int line, char const *expr)
{
ERROR("ASSERT FAILED %s[%u]: %s", file, line, expr);
- abort();
+ fr_fault(SIGABRT);
+ fr_exit_now(1);
}
request->username = NULL;
request->password = NULL;
request->timestamp = time(NULL);
- request->options = debug_flag; /* Default to global debug level */
+ request->log.lvl = debug_flag; /* Default to global debug level */
request->module = "";
request->component = "<core>";
- request->radlog = radlog_request;
+ request->log.func = vradlog_request;
return request;
}
*/
fake->server = request->server;
- fake->packet = rad_alloc(request, 1);
+ fake->packet = rad_alloc(fake, 1);
if (!fake->packet) {
request_free(&fake);
return NULL;
}
- fake->reply = rad_alloc(request, 0);
+ fake->reply = rad_alloc(fake, 0);
if (!fake->reply) {
request_free(&fake);
return NULL;
/*
* Copy debug information.
*/
- fake->options = request->options;
- fake->radlog = request->radlog;
+ memcpy(&(fake->log), &(request->log), sizeof(fake->log));
return fake;
}
/*
* Originate CoA requests only when necessary.
*/
- if ((request->packet->code != PW_AUTHENTICATION_REQUEST) &&
- (request->packet->code != PW_ACCOUNTING_REQUEST)) return NULL;
+ if ((request->packet->code != PW_CODE_AUTHENTICATION_REQUEST) &&
+ (request->packet->code != PW_CODE_ACCOUNTING_REQUEST)) return NULL;
request->coa = request_alloc_fake(request);
if (!request->coa) return NULL;
#define USEC 1000000
#endif
-int rad_pps(int *past, int *present, time_t *then, struct timeval *now)
+uint32_t rad_pps(uint32_t *past, uint32_t *present, time_t *then, struct timeval *now)
{
- int pps;
+ uint32_t pps;
if (*then != now->tv_sec) {
*then = now->tv_sec;
* We have to have SOMETHING, at least.
*/
if (argc <= 0) {
- ERROR("rad_expand_xlat: Empty command line.");
+ ERROR("rad_expand_xlat: Empty command line");
return -1;
}
left--;
if (left <= 0) {
- ERROR("rad_expand_xlat: Ran out of space while expanding arguments.");
+ ERROR("rad_expand_xlat: Ran out of space while expanding arguments");
return -1;
}
}
const FR_NAME_NUMBER pair_lists[] = {
{ "request", PAIR_LIST_REQUEST },
{ "reply", PAIR_LIST_REPLY },
+ { "control", PAIR_LIST_CONTROL }, /* New name should have priority */
{ "config", PAIR_LIST_CONTROL },
- { "control", PAIR_LIST_CONTROL },
#ifdef WITH_PROXY
{ "proxy-request", PAIR_LIST_PROXY_REQUEST },
{ "proxy-reply", PAIR_LIST_PROXY_REPLY },
* @see dict_attrbyname
*
* @param[in,out] name of attribute.
- * @param[in] unknown the list to return if no qualifiers were found.
+ * @param[in] default_list the list to return if no qualifiers were found.
* @return PAIR_LIST_UNKOWN if qualifiers couldn't be resolved to a list.
*/
-pair_lists_t radius_list_name(char const **name, pair_lists_t unknown)
+pair_lists_t radius_list_name(char const **name, pair_lists_t default_list)
{
char const *p = *name;
char const *q;
rad_assert(name && *name);
/*
- * We couldn't determine the list if:
- *
- * A colon delimiter was found, but the next char was a
- * number, indicating a tag, not a list qualifier.
- *
- * No colon was found and the first char was upper case
- * indicating an attribute.
- *
+ * Unfortunately, ':' isn't a definitive separator for
+ * the list name. We may have numeric tags, too.
*/
q = strchr(p, ':');
- if (((q && (q[1] >= '0') && (q[1] <= '9'))) ||
- (!q && isupper((int) *p))) {
- return unknown;
- }
-
if (q) {
- *name = (q + 1); /* Consume the list and delimiter */
- return fr_substr2int(pair_lists, p, PAIR_LIST_UNKNOWN, (q - p));
+ /*
+ * Check for tagged attributes. They have
+ * "name:tag", where tag is a decimal number.
+ * Valid tags are invalid attributes, so that's
+ * OK.
+ *
+ * Also allow "name:tag[#]" as a tag.
+ *
+ * However, "request:" is allowed, too, and
+ * shouldn't be interpreted as a tag.
+ *
+ * We do this check first rather than just
+ * looking up the request name, because this
+ * check is cheap, and looking up the request
+ * name is expensive.
+ */
+ if (isdigit((int) q[1])) {
+ char const *d = q + 1;
+
+ while (isdigit((int) *d)) {
+ d++;
+ }
+
+ /*
+ * Return the DEFAULT list as supplied by
+ * the caller. This is usually
+ * PAIRLIST_REQUEST.
+ */
+ if (!*d || (*d == '[')) {
+ return default_list;
+ }
+ }
+
+ /*
+ * If the first part is a list name, then treat
+ * it as a list. This means that we CANNOT have
+ * an attribute which is named "request",
+ * "reply", etc. Allowing a tagged attribute
+ * "request:3" would just be insane.
+ */
+ output = fr_substr2int(pair_lists, p, PAIR_LIST_UNKNOWN, (q - p));
+ if (output != PAIR_LIST_UNKNOWN) {
+ *name = (q + 1); /* Consume the list and delimiter */
+ return output;
+ }
+
+ /*
+ * It's not a known list, say so.
+ */
+ return PAIR_LIST_UNKNOWN;
}
- q = (p + strlen(p)); /* Consume the entire string */
+ /*
+ * The input string may be just a list name,
+ * e.g. "request". Check for that.
+ */
+ q = (p + strlen(p));
output = fr_substr2int(pair_lists, p, PAIR_LIST_UNKNOWN, (q - p));
if (output != PAIR_LIST_UNKNOWN) {
*name = q;
return output;
}
- return unknown;
+ /*
+ * It's just an attribute name. Return the default list
+ * as supplied by the caller.
+ */
+ return default_list;
}
}
}
+#ifndef NDEBUG
+/*
+ * Verify a packet.
+ */
+static void verify_packet(REQUEST *request, RADIUS_PACKET *packet)
+{
+ TALLOC_CTX *parent;
+
+ if (!packet) return;
+
+ parent = talloc_parent(packet);
+ if (parent != request) {
+ ERROR("Expected RADIUS_PACKET to be parented by %p (%s), "
+ "but parented by %p (%s)",
+ request, talloc_get_name(request),
+ parent, parent ? talloc_get_name(parent) : "NULL");
+
+ fr_log_talloc_report(packet);
+ if (parent) fr_log_talloc_report(parent);
+
+ rad_assert(0);
+ }
+
+ VERIFY_PACKET(packet);
+
+ if (!packet->vps) return;
+
+#ifdef WITH_VERIFY_PTR
+ fr_verify_list(packet, packet->vps);
+#endif
+}
+/*
+ * Catch horrible talloc errors.
+ */
+void verify_request(REQUEST *request)
+{
+ if (!request) return;
+
+ (void) talloc_get_type_abort(request, REQUEST);
+
+#ifdef WITH_VERIFY_PTR
+ fr_verify_list(request, request->config_items);
+#endif
+
+ if (request->packet) verify_packet(request, request->packet);
+ if (request->reply) verify_packet(request, request->reply);
+#ifdef WITH_PROXY
+ if (request->proxy) verify_packet(request, request->proxy);
+ if (request->proxy_reply) verify_packet(request, request->proxy_reply);
+#endif
+
+#ifdef WITH_COA
+ if (request->coa) {
+ void *parent;
+
+ (void) talloc_get_type_abort(request->coa, REQUEST);
+ parent = talloc_parent(request->coa);
+
+ rad_assert(parent == request);
+
+ verify_request(request->coa);
+ }
+#endif
+}
+#endif
* Tagged attributes are equal if and only if both the
* tag AND value match.
*/
- if (check->da->flags.has_tag) {
+ if (check->da->flags.has_tag && !TAG_EQ(check->tag, vp->tag)) {
ret = ((int) vp->tag) - ((int) check->tag);
- goto finish;
+ if (ret != 0) goto finish;
}
/*
ret = vp->vp_date - check->vp_date;
break;
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
ret = ntohl(vp->vp_ipaddr) - ntohl(check->vp_ipaddr);
break;
- case PW_TYPE_IPV6ADDR:
+ case PW_TYPE_IPV6_ADDR:
ret = memcmp(&vp->vp_ipv6addr, &check->vp_ipv6addr,
sizeof(vp->vp_ipv6addr));
break;
- case PW_TYPE_IPV6PREFIX:
+ case PW_TYPE_IPV6_PREFIX:
ret = memcmp(&vp->vp_ipv6prefix, &check->vp_ipv6prefix,
sizeof(vp->vp_ipv6prefix));
break;
/** Find a comparison function for two attributes.
*
- * @todo this should probably take DA's.
* @param da to find comparison function for.
* @return true if a comparison function was found, else false.
*/
int compare;
bool first_only;
- for (check_item = paircursor(&cursor, &check);
+ for (check_item = fr_cursor_init(&cursor, &check);
check_item;
- check_item = pairnext(&cursor)) {
+ check_item = fr_cursor_next(&cursor)) {
/*
* If the user is setting a configuration value,
* then don't bother comparing it to any attributes
*/
case PW_USER_PASSWORD:
if (check_item->op == T_OP_CMP_EQ) {
- WDEBUG("Found User-Password == \"...\".");
- WDEBUG("Are you sure you don't mean Cleartext-Password?");
- WDEBUG("See \"man rlm_pap\" for more information.");
+ WARN("Found User-Password == \"...\"");
+ WARN("Are you sure you don't mean Cleartext-Password?");
+ WARN("See \"man rlm_pap\" for more information");
}
if (pairfind(req_list, PW_USER_PASSWORD, 0, TAG_ANY) == NULL) {
continue;
len = radius_xlat(buffer, sizeof(buffer), request, vp->value.xlat, NULL, NULL);
-
rad_const_free(vp->value.xlat);
vp->value.xlat = NULL;
if (len < 0) {
/*
* Parse the string into a new value.
*/
- if (!pairparsevalue(vp, buffer)){
+ if (pairparsevalue(vp, buffer, 0) < 0){
return -2;
}
return 0;
}
-/** Move pairs, replacing/over-writing them, and doing xlat.
- *
- * Move attributes from one list to the other if not already present.
- */
-void radius_xlat_move(REQUEST *request, VALUE_PAIR **to, VALUE_PAIR **from)
-{
- VALUE_PAIR **tailto, *i, *j, *next;
- VALUE_PAIR *tailfrom = NULL;
- VALUE_PAIR *found;
-
- /*
- * Point "tailto" to the end of the "to" list.
- */
- tailto = to;
- for (i = *to; i; i = i->next) {
- tailto = &i->next;
- }
-
- /*
- * Loop over the "from" list.
- */
- for (i = *from; i; i = next) {
- next = i->next;
-
- /*
- * Don't move 'fallthrough' over.
- */
- if (!i->da->vendor && i->da->attr == PW_FALL_THROUGH) {
- tailfrom = i;
- continue;
- }
-
- /*
- * We've got to xlat the string before moving
- * it over.
- */
- radius_xlat_do(request, i);
-
- found = pairfind(*to, i->da->attr, i->da->vendor, TAG_ANY);
- switch (i->op) {
-
- /*
- * If a similar attribute is found,
- * delete it.
- */
- case T_OP_SUB: /* -= */
- if (found) {
- if (!i->vp_strvalue[0] ||
- (strcmp(found->vp_strvalue,
- i->vp_strvalue) == 0)) {
- pairdelete(to, found->da->attr,
- found->da->vendor,
- found->tag);
-
- /*
- * 'tailto' may have been
- * deleted...
- */
- tailto = to;
- for (j = *to; j; j = j->next) {
- tailto = &j->next;
- }
- }
- }
- tailfrom = i;
- continue;
-
- /*
- * Add it, if it's not already there.
- */
- case T_OP_EQ: /* = */
- if (found) {
- tailfrom = i;
- continue; /* with the loop */
- }
- break;
-
- /*
- * If a similar attribute is found,
- * replace it with the new one. Otherwise,
- * add the new one to the list.
- */
- case T_OP_SET: /* := */
- if (found) {
- VALUE_PAIR *vp;
-
- vp = found->next;
- memcpy(found, i, sizeof(*found));
- found->next = vp;
- tailfrom = i;
- continue;
- }
- break;
-
- /*
- * FIXME: Add support for <=, >=, <, >
- *
- * which will mean (for integers)
- * 'make the attribute the smaller, etc'
- */
-
- /*
- * Add the new element to the list, even
- * if similar ones already exist.
- */
- default:
- case T_OP_ADD: /* += */
- break;
- }
-
- if (tailfrom) {
- tailfrom->next = next;
- } else {
- *from = next;
- }
-
- /*
- * If ALL of the 'to' attributes have been deleted,
- * then ensure that the 'tail' is updated to point
- * to the head.
- */
- if (!*to) {
- tailto = to;
- }
- *tailto = i;
- if (i) {
- i->next = NULL;
- tailto = &i->next;
- }
- } /* loop over the 'from' list */
-}
-
/** Create a VALUE_PAIR and add it to a list of VALUE_PAIR s
*
* @note This function ALWAYS returns. If we're OOM, then it causes the
* @note server to exit, so you don't need to check the return value.
*
- * @param[in] request Current request.
+ * @param[in] ctx for talloc
* @param[out] vps List to add new VALUE_PAIR to, if NULL will just
* return VALUE_PAIR.
* @param[in] attribute number.
* @param[in] vendor number.
* @return a new VLAUE_PAIR or causes server to exit on error.
*/
-VALUE_PAIR *radius_paircreate(REQUEST *request, VALUE_PAIR **vps,
+VALUE_PAIR *radius_paircreate(TALLOC_CTX *ctx, VALUE_PAIR **vps,
unsigned int attribute, unsigned int vendor)
{
VALUE_PAIR *vp;
- /*
- * FIXME: the context should ideally be the packet...
- */
- vp = paircreate(request, attribute, vendor);
+ vp = paircreate(ctx, attribute, vendor);
if (!vp) {
ERROR("No memory!");
rad_assert("No memory" == NULL);
vp_cursor_t cursor;
if (!vp || !debug_flag || !fr_log_fp) return;
- for (vp = paircursor(&cursor, &vp);
+ for (vp = fr_cursor_init(&cursor, &vp);
vp;
- vp = pairnext(&cursor)) {
- /*
- * Take this opportunity to verify all the VALUE_PAIRs are still valid.
- */
- if (!talloc_get_type(vp, VALUE_PAIR)) {
- ERROR("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp));
-
- log_talloc_report(vp);
- rad_assert(0);
- }
-
+ vp = fr_cursor_next(&cursor)) {
vp_print(fr_log_fp, vp);
}
fflush(fr_log_fp);
{
vp_cursor_t cursor;
char buffer[256];
- if (!vp || !request || !request->radlog) return;
+ if (!vp || !request || !request->log.func) return;
- for (vp = paircursor(&cursor, &vp);
+ for (vp = fr_cursor_init(&cursor, &vp);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
/*
* Take this opportunity to verify all the VALUE_PAIRs are still valid.
*/
if (!talloc_get_type(vp, VALUE_PAIR)) {
REDEBUG("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp));
- log_talloc_report(vp);
+ fr_log_talloc_report(vp);
rad_assert(0);
}
vp_prints(buffer, sizeof(buffer), vp);
-
- request->radlog(L_DBG, level, request, "\t%s", buffer);
+ RDEBUGX(level, "\t%s", buffer);
}
}
#ifdef WITH_COA
case PAIR_LIST_COA:
if (request->coa &&
- (request->coa->proxy->code == PW_COA_REQUEST)) {
+ (request->coa->proxy->code == PW_CODE_COA_REQUEST)) {
return &request->coa->proxy->vps;
}
break;
case PAIR_LIST_COA_REPLY:
if (request->coa && /* match reply with request */
- (request->coa->proxy->code == PW_COA_REQUEST) &&
+ (request->coa->proxy->code == PW_CODE_COA_REQUEST) &&
request->coa->proxy_reply) {
return &request->coa->proxy_reply->vps;
}
case PAIR_LIST_DM:
if (request->coa &&
- (request->coa->proxy->code == PW_DISCONNECT_REQUEST)) {
+ (request->coa->proxy->code == PW_CODE_DISCONNECT_REQUEST)) {
return &request->coa->proxy->vps;
}
break;
case PAIR_LIST_DM_REPLY:
if (request->coa && /* match reply with request */
- (request->coa->proxy->code == PW_DISCONNECT_REQUEST) &&
+ (request->coa->proxy->code == PW_CODE_DISCONNECT_REQUEST) &&
request->coa->proxy_reply) {
- return &request->coa->proxy->vps;
+ return &request->coa->proxy->vps;
}
break;
#endif
return NULL;
}
+
+TALLOC_CTX *radius_list_ctx(REQUEST *request, pair_lists_t list_name)
+{
+ if (!request) return NULL;
+
+ switch (list_name) {
+ case PAIR_LIST_REQUEST:
+ return request->packet;
+
+ case PAIR_LIST_REPLY:
+ return request->reply;
+
+ case PAIR_LIST_CONTROL:
+ return request;
+
+#ifdef WITH_PROXY
+ case PAIR_LIST_PROXY_REQUEST:
+ return request->proxy;
+
+ case PAIR_LIST_PROXY_REPLY:
+ return request->proxy_reply;
+#endif
+
+#ifdef WITH_COA
+ case PAIR_LIST_COA:
+ if (!request->coa) return NULL;
+ rad_assert(request->coa->proxy != NULL);
+ if (request->coa->proxy->code != PW_CODE_COA_REQUEST) return NULL;
+ return request->coa->proxy;
+
+ case PAIR_LIST_COA_REPLY:
+ if (!request->coa) return NULL;
+ rad_assert(request->coa->proxy != NULL);
+ if (request->coa->proxy->code != PW_CODE_COA_REQUEST) return NULL;
+ return request->coa->proxy_reply;
+
+ case PAIR_LIST_DM:
+ if (!request->coa) return NULL;
+ rad_assert(request->coa->proxy != NULL);
+ if (request->coa->proxy->code != PW_CODE_DISCONNECT_REQUEST) return NULL;
+ return request->coa->proxy;
+
+ case PAIR_LIST_DM_REPLY:
+ if (!request->coa) return NULL;
+ rad_assert(request->coa->proxy != NULL);
+ if (request->coa->proxy->code != PW_CODE_DISCONNECT_REQUEST) return NULL;
+ return request->coa->proxy_reply;
+#endif
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+/*
+ * Debug print a map / VP
+ */
+void radius_map_debug(REQUEST *request, value_pair_map_t const *map, VALUE_PAIR const *vp)
+{
+ char *value;
+ char buffer[1024];
+
+ rad_assert(vp || (map->src->type == VPT_TYPE_NULL));
+
+ switch (map->src->type) {
+ /*
+ * Just print the value being assigned
+ */
+ default:
+ case VPT_TYPE_LITERAL:
+ vp_prints_value(buffer, sizeof(buffer), vp, '\'');
+ value = buffer;
+ break;
+
+ case VPT_TYPE_XLAT:
+ case VPT_TYPE_XLAT_STRUCT:
+ vp_prints_value(buffer, sizeof(buffer), vp, '"');
+ value = buffer;
+ break;
+
+ case VPT_TYPE_DATA:
+ vp_prints_value(buffer, sizeof(buffer), vp, '\'');
+ value = buffer;
+ break;
+
+ /*
+ * Just printing the value doesn't make sense, but we still
+ * want to know what it was...
+ */
+ case VPT_TYPE_LIST:
+ vp_prints_value(buffer, sizeof(buffer), vp, '\'');
+
+ if (map->src->vpt_request == REQUEST_OUTER) {
+ value = talloc_typed_asprintf(request, "&outer.%s:%s -> %s",
+ fr_int2str(pair_lists, map->src->vpt_list, "<INVALID>"),
+ vp->da->name, buffer);
+ } else {
+ value = talloc_typed_asprintf(request, "&%s:%s -> %s",
+ fr_int2str(pair_lists, map->src->vpt_list, "<INVALID>"),
+ vp->da->name, buffer);
+ }
+ break;
+
+ case VPT_TYPE_ATTR:
+ vp_prints_value(buffer, sizeof(buffer), vp, '\'');
+ value = talloc_typed_asprintf(request, "&%s -> %s", map->src->vpt_da->name, buffer);
+ break;
+
+ case VPT_TYPE_NULL:
+ strcpy(buffer, "ANY");
+ value = buffer;
+ break;
+ }
+
+ switch (map->dst->type) {
+ case VPT_TYPE_LIST:
+ RDEBUG("\t%s%s %s %s", map->dst->name, vp ? vp->da->name : "",
+ fr_int2str(fr_tokens, vp ? vp->op : map->op, "<INVALID>"), value);
+ break;
+
+ case VPT_TYPE_ATTR:
+ RDEBUG("\t%s %s %s", map->dst->name,
+ fr_int2str(fr_tokens, vp ? vp->op : map->op, "<INVALID>"), value);
+ break;
+
+ default:
+ break;
+ }
+
+ if (value != buffer) talloc_free(value);
+}
+
+#define DEBUG_OVERWRITE(_old, _new) \
+do {\
+ if (RDEBUG_ENABLED3) {\
+ char *old = vp_aprint_value(request, _old);\
+ char *new = vp_aprint_value(request, _new);\
+ RDEBUG3("Overwriting value \"%s\" with \"%s\"", old, new);\
+ talloc_free(old);\
+ talloc_free(new);\
+ }\
+} while (0)
+
/** Convert value_pair_map_t to VALUE_PAIR(s) and add them to a REQUEST.
*
* Takes a single value_pair_map_t, resolves request and list identifiers
* @param func to retrieve module specific values and convert them to
* VALUE_PAIRS.
* @param ctx to be passed to func.
- * @param src name to be used in debugging if different from map value.
* @return -1 if the operation failed, -2 in the source attribute wasn't valid, 0 on success.
*/
-int radius_map2request(REQUEST *request, value_pair_map_t const *map,
- UNUSED char const *src, radius_tmpl_getvalue_t func, void *ctx)
+int radius_map2request(REQUEST *request, value_pair_map_t const *map, radius_tmpl_getvalue_t func, void *ctx)
{
- int rcode;
- vp_cursor_t cursor;
- VALUE_PAIR **list, *vp, *head = NULL;
+ int rcode = 0;
+ int num;
+ VALUE_PAIR **list, *vp, *dst, *head = NULL;
+ bool found = false;
REQUEST *context;
- char buffer[1024];
+ TALLOC_CTX *parent;
+ vp_cursor_t dst_list, src_list;
+
+ /*
+ * Sanity check inputs. We can have a list or attribute
+ * as a destination.
+ */
+ if ((map->dst->type != VPT_TYPE_LIST) &&
+ (map->dst->type != VPT_TYPE_ATTR)) {
+ REDEBUG("Invalid mapping destination");
+ return -2;
+ }
context = request;
- if (radius_request(&context, map->dst->request) < 0) {
+ if (radius_request(&context, map->dst->vpt_request) < 0) {
REDEBUG("Mapping \"%s\" -> \"%s\" invalid in this context", map->src->name, map->dst->name);
-
return -2;
}
- list = radius_list(context, map->dst->list);
+ /*
+ * If there's no CoA packet and we're updating it,
+ * auto-allocate it.
+ */
+ if (((map->dst->vpt_list == PAIR_LIST_COA) ||
+ (map->dst->vpt_list == PAIR_LIST_DM)) && !request->coa) {
+ request_alloc_coa(context);
+ context->coa->proxy->code = (map->dst->vpt_list == PAIR_LIST_COA) ?
+ PW_CODE_COA_REQUEST :
+ PW_CODE_DISCONNECT_REQUEST;
+ }
+
+ list = radius_list(context, map->dst->vpt_list);
if (!list) {
REDEBUG("Mapping \"%s\" -> \"%s\" invalid in this context", map->src->name, map->dst->name);
return -2;
}
+ parent = radius_list_ctx(context, map->dst->vpt_list);
+ rad_assert(parent);
/*
- * The callback should either return -1 to signify operations error, -2 when it can't find the
- * attribute or list being referenced, or 0 to signify success.
- * It may return "sucess", but still have no VPs to work with.
- * Only if it returned an error code should it not write anything to the head pointer.
+ * The callback should either return -1 to signify operations error,
+ * -2 when it can't find the attribute or list being referenced, or
+ * 0 to signify success. It may return "sucess", but still have no
+ * VPs to work with.
*/
- rcode = func(&head, request, map, ctx);
- if (rcode < 0) {
- rad_assert(!head);
+ if (map->src->type != VPT_TYPE_NULL) {
+ rcode = func(&head, request, map, ctx);
+ if (rcode < 0) {
+ rad_assert(!head);
+ return rcode;
+ }
+ if (!head) return rcode;
+ } else {
+ if (debug_flag) radius_map_debug(request, map, NULL);
+ }
- return rcode;
+ /*
+ * Reparent the VPs (func may return multiple)
+ */
+ for (vp = fr_cursor_init(&src_list, &head);
+ vp;
+ vp = fr_cursor_next(&src_list)) {
+ VERIFY_VP(vp);
+
+ if (debug_flag) radius_map_debug(request, map, vp);
+ (void) talloc_steal(parent, vp);
}
- if (!head) return 0;
+ /*
+ * The destination is a list (which is a completely different set of operations)
+ */
+ if (map->dst->type == VPT_TYPE_LIST) {
+ switch (map->op) {
+ case T_OP_CMP_FALSE:
+ /* We don't need the src VPs (should just be 'ANY') */
+ rad_assert(!head);
+
+ /* Clear the entire dst list */
+ pairfree(list);
+
+ if (map->dst->vpt_list == PAIR_LIST_REQUEST) {
+ context->username = NULL;
+ context->password = NULL;
+ }
+ return 0;
- VERIFY_VP(head);
+ case T_OP_SET:
+ if (map->src->type == VPT_TYPE_LIST) {
+ pairfree(list);
+ *list = head;
+ } else {
+ case T_OP_EQ:
+ rad_assert(map->src->type == VPT_TYPE_EXEC);
+ pairmove(parent, list, &head);
+ pairfree(&head);
+ }
+ goto finish;
- if (debug_flag) for (vp = paircursor(&cursor, &head); vp; vp = pairnext(&cursor)) {
- char *value;
+ case T_OP_ADD:
+ pairadd(list, head);
+ head = NULL;
+ goto finish;
- switch (map->src->type) {
- /*
- * Just print the value being assigned
- */
- default:
+ default:
+ pairfree(&head);
+ return -1;
+ }
+ }
- case VPT_TYPE_LITERAL:
- vp_prints_value(buffer, sizeof(buffer), vp, '\'');
- value = buffer;
- break;
- case VPT_TYPE_XLAT:
- vp_prints_value(buffer, sizeof(buffer), vp, '"');
- value = buffer;
- break;
- case VPT_TYPE_DATA:
- vp_prints_value(buffer, sizeof(buffer), vp, 0);
- value = buffer;
- break;
- /*
- * Just printing the value doesn't make sense, but we still
- * want to know what it was...
- */
- case VPT_TYPE_LIST:
- vp_prints_value(buffer, sizeof(buffer), vp, '\'');
- value = talloc_asprintf(request, "&%s%s -> %s", map->src->name, vp->da->name, buffer);
- break;
- case VPT_TYPE_ATTR:
- vp_prints_value(buffer, sizeof(buffer), vp, '\'');
- value = talloc_asprintf(request, "&%s -> %s", map->src->name, buffer);
- break;
+ /*
+ * Find the destination attribute. We leave with either
+ * the dst_list and vp pointing to the attribute or the VP
+ * being NULL (no attribute at that index).
+ */
+ num = map->dst->vpt_num;
+ (void) fr_cursor_init(&dst_list, list);
+ if (num != NUM_ANY) {
+ while ((dst = fr_cursor_next_by_da(&dst_list, map->dst->vpt_da, map->dst->vpt_tag))) {
+ if (num-- == 0) break;
+ }
+ } else {
+ dst = fr_cursor_next_by_da(&dst_list, map->dst->vpt_da, map->dst->vpt_tag);
+ }
+ rad_assert(!dst || (map->dst->vpt_da == dst->da));
+
+ /*
+ * The destination is an attribute
+ */
+ switch (map->op) {
+ default:
+ break;
+ /*
+ * !* - Remove all attributes which match dst in the specified list.
+ * This doesn't use attributes returned by the func(), and immediately frees them.
+ */
+ case T_OP_CMP_FALSE:
+ /* We don't need the src VPs (should just be 'ANY') */
+ rad_assert(!head);
+ if (!dst) return 0;
+
+ /*
+ * Wildcard: delete all of the matching ones, based on tag.
+ */
+ if (map->dst->vpt_num == NUM_ANY) {
+ pairdelete(list, map->dst->vpt_da->attr, map->dst->vpt_da->vendor, map->dst->vpt_tag);
+ dst = NULL;
+ /*
+ * We've found the Nth one. Delete it, and only it.
+ */
+ } else {
+ dst = fr_cursor_remove(&dst_list);
+ pairfree(&dst);
}
+ /*
+ * Check that the User-Name and User-Password
+ * caches point to the correct attribute.
+ */
+ goto finish;
+
+ /*
+ * -= - Delete attributes in the dst list which match any of the
+ * src_list attributes.
+ *
+ * This operation has two modes:
+ * - If map->dst->vpt_num > 0, we check each of the src_list attributes against
+ * the dst attribute, to see if any of their values match.
+ * - If map->dst->vpt_num == NUM_ANY, we compare all instances of the dst attribute
+ * against each of the src_list attributes.
+ */
+ case T_OP_SUB:
+ /* We didn't find any attributes earlier */
+ if (!dst) {
+ pairfree(&head);
+ return 0;
+ }
+
+ /*
+ * Instance specific[n] delete
+ */
+ if (map->dst->vpt_num != NUM_ANY) {
+ for (vp = fr_cursor_first(&src_list);
+ vp;
+ vp = fr_cursor_next(&src_list)) {
+ head->op = T_OP_CMP_EQ;
+ rcode = radius_compare_vps(request, vp, dst);
+ if (rcode == 0) {
+ dst = fr_cursor_remove(&dst_list);
+ pairfree(&dst);
+ found = true;
+ }
+ }
+ pairfree(&head);
+ if (!found) return 0;
+ goto finish;
+ }
- RDEBUG("\t\t%s %s %s", map->dst->name, fr_int2str(fr_tokens, vp->op, "<INVALID>"), value);
+ /*
+ * All instances[*] delete
+ */
+ for (dst = fr_cursor_current(&dst_list);
+ dst;
+ dst = fr_cursor_next_by_da(&dst_list, map->dst->vpt_da, map->dst->vpt_tag)) {
+ for (vp = fr_cursor_first(&src_list);
+ vp;
+ vp = fr_cursor_next(&src_list)) {
+ head->op = T_OP_CMP_EQ;
+ rcode = radius_compare_vps(request, vp, dst);
+ if (rcode == 0) {
+ dst = fr_cursor_remove(&dst_list);
+ pairfree(&dst);
+ found = true;
+ }
+ }
+ }
+ pairfree(&head);
+ if (!found) return 0;
+ goto finish;
+ }
- if (value != buffer) talloc_free(value);
+ /*
+ * Another fixup pass to set tags on attributes were about to insert
+ */
+ if (map->dst->vpt_tag != TAG_ANY) {
+ for (vp = fr_cursor_init(&src_list, &head);
+ vp;
+ vp = fr_cursor_next(&src_list)) {
+ vp->tag = map->dst->vpt_tag;
+ }
}
+ switch (map->op) {
/*
- * Use pairmove so the operator is respected
+ * = - Set only if not already set
*/
- radius_pairmove(context, list, head);
+ case T_OP_EQ:
+ if (dst) {
+ RDEBUG3("Refusing to overwrite (use :=)");
+ pairfree(&head);
+ return 0;
+ }
+
+ /* Insert first instance (if multiple) */
+ fr_cursor_first(&src_list);
+ fr_cursor_insert(&dst_list, fr_cursor_remove(&src_list));
+ /* Free any we didn't insert */
+ pairfree(&head);
+ break;
+
+ /*
+ * := - Overwrite existing attribute with last src_list attribute
+ */
+ case T_OP_SET:
+ /* Wind to last instance */
+ fr_cursor_last(&src_list);
+ if (dst) {
+ dst = fr_cursor_remove(&dst_list);
+ DEBUG_OVERWRITE(dst, fr_cursor_current(&src_list));
+ pairfree(&dst);
+ }
+ fr_cursor_insert(&dst_list, fr_cursor_remove(&src_list));
+ /* Free any we didn't insert */
+ pairfree(&head);
+ break;
+
+ /*
+ * += - Add all src_list attributes to the destination
+ */
+ case T_OP_ADD:
+ /* Insert all the instances! (if multiple) */
+ pairadd(list, head);
+ head = NULL;
+ break;
+
+ /*
+ * Filtering operators
+ */
+ default:
+ /*
+ * If the dst doesn't exist, the filters will add
+ * it with the given value.
+ */
+ if (!dst) {
+ RDEBUG3("No existing attribute to filter, adding instead");
+ fr_cursor_insert(&dst_list, head);
+ head = NULL;
+ goto finish;
+ }
+
+ /*
+ * The LHS exists. We need to limit it's value based on
+ * the operator, and the value of the RHS.
+ */
+ found = false;
+ for (vp = fr_cursor_first(&src_list);
+ vp;
+ vp = fr_cursor_next(&src_list)) {
+ vp->op = map->op;
+ rcode = radius_compare_vps(request, vp, dst);
+ vp->op = T_OP_SET;
+
+ switch (map->op) {
+ case T_OP_CMP_EQ:
+ if (rcode == 0) continue;
+ replace:
+ dst = fr_cursor_remove(&dst_list);
+ DEBUG_OVERWRITE(dst, fr_cursor_current(&src_list));
+ pairfree(&dst);
+ fr_cursor_insert(&dst_list, fr_cursor_remove(&src_list));
+ found = true;
+ continue;
+
+ case T_OP_LE:
+ if (rcode <= 0) continue;
+ goto replace;
+
+ case T_OP_GE:
+ if (rcode >= 0) continue;
+ goto replace;
+
+ default:
+ pairfree(&head);
+ return -1;
+ }
+ }
+ pairfree(&head);
+ if (!found) return 0;
+
+ break;
+ }
+
+finish:
+ rad_assert(!head);
+
+ if (map->dst->vpt_list == PAIR_LIST_REQUEST) {
+ context->username = pairfind(*list, PW_USER_NAME, 0, TAG_ANY);
+ context->password = pairfind(*list, PW_USER_PASSWORD, 0, TAG_ANY);
+ }
return 0;
}
char *expanded = NULL;
char answer[1024];
VALUE_PAIR **input_pairs = NULL;
- VALUE_PAIR **output_pairs = NULL;
+ VALUE_PAIR *output_pairs = NULL;
*out = NULL;
* if dst is an attribute, then we create an attribute of that type and then
* call pairparsevalue on the output of the script.
*/
- out[0] = '\0';
result = radius_exec_program(request, map->src->name, true, true,
answer, sizeof(answer), EXEC_TIMEOUT,
input_pairs ? *input_pairs : NULL,
- (map->dst->type == VPT_TYPE_LIST) ? output_pairs : NULL);
+ (map->dst->type == VPT_TYPE_LIST) ? &output_pairs : NULL);
talloc_free(expanded);
if (result != 0) {
- REDEBUG("%s", answer);
talloc_free(output_pairs);
return -1;
}
switch (map->dst->type) {
case VPT_TYPE_LIST:
if (!output_pairs) {
+ REDEBUG("No valid attributes received from program");
return -2;
}
- *out = *output_pairs;
+ *out = output_pairs;
return 0;
case VPT_TYPE_ATTR:
- {
- VALUE_PAIR *vp;
+ {
+ VALUE_PAIR *vp;
- vp = pairalloc(request, map->dst->da);
- if (!vp) return -1;
- vp->op = map->op;
- if (!pairparsevalue(vp, answer)) {
- pairfree(&vp);
- return -2;
- }
- *out = vp;
-
- return 0;
+ vp = pairalloc(request, map->dst->vpt_da);
+ if (!vp) return -1;
+ vp->op = map->op;
+ if (pairparsevalue(vp, answer, 0) < 0) {
+ pairfree(&vp);
+ return -2;
}
+ *out = vp;
+
+ return 0;
+ }
default:
rad_assert(0);
}
/** Convert a map to a VALUE_PAIR.
*
- * @param[out] out Where to write the VALUE_PAIR(s).
+ * @param[out] out Where to write the VALUE_PAIR(s), which may be NULL if not found
* @param[in] request structure (used only for talloc)
* @param[in] map the map. The LHS (dst) has to be VPT_TYPE_ATTR or VPT_TYPE_LIST.
* @param[in] ctx unused
- * @return 0 on success, -1 on failure, -2 on attribute not found/equivalent
+ * @return 0 on success, -1 on failure
*/
int radius_map2vp(VALUE_PAIR **out, REQUEST *request, value_pair_map_t const *map, UNUSED void *ctx)
{
int rcode = 0;
VALUE_PAIR *vp = NULL, *found, **from = NULL;
DICT_ATTR const *da;
- REQUEST *context;
+ REQUEST *context = request;
vp_cursor_t cursor;
- rad_assert(request != NULL);
- rad_assert(map != NULL);
-
*out = NULL;
/*
- * Special case for !*, we don't need to parse the value, just allocate an attribute with
- * the right operator.
+ * Special case for !*, we don't need to parse RHS as this is a unary operator.
*/
- if (map->op == T_OP_CMP_FALSE) {
- vp = pairalloc(request, map->dst->da);
- if (!vp) return -1;
- vp->op = map->op;
- *out = vp;
-
- return 0;
- }
+ if (map->op == T_OP_CMP_FALSE) return 0;
/*
* List to list found, this is a special case because we don't need
- * to allocate any attributes, just found the current list, and change
+ * to allocate any attributes, just finding the current list, and change
* the op.
*/
if ((map->dst->type == VPT_TYPE_LIST) && (map->src->type == VPT_TYPE_LIST)) {
- from = radius_list(request, map->src->list);
- if (!from) return -2;
+ if (radius_request(&context, map->src->vpt_request) == 0) {
+ from = radius_list(context, map->src->vpt_list);
+ }
+ if (!from) return 0;
found = paircopy(request, *from);
+
/*
- * List to list copy is invalid if the src list has no attributes.
+ * List to list copy is empty if the src list has no attributes.
*/
- if (!found) return -2;
+ if (!found) return 0;
- for (vp = paircursor(&cursor, &found);
+ for (vp = fr_cursor_init(&cursor, &found);
vp;
- vp = pairnext(&cursor)) {
- vp->op = T_OP_ADD;
+ vp = fr_cursor_next(&cursor)) {
+ vp->op = T_OP_ADD;
}
*out = found;
}
/*
- * Deal with all non-list founding operations.
+ * Deal with all non-list operations.
*/
- da = map->dst->da ? map->dst->da : map->src->da;
+ da = map->dst->vpt_da ? map->dst->vpt_da : map->src->vpt_da;
switch (map->src->type) {
case VPT_TYPE_XLAT:
+ case VPT_TYPE_XLAT_STRUCT:
case VPT_TYPE_LITERAL:
case VPT_TYPE_DATA:
vp = pairalloc(request, da);
* And parse the RHS
*/
switch (map->src->type) {
- case VPT_TYPE_XLAT:
- rad_assert(map->dst->da); /* Need to know where were going to write the new attribute */
- /*
- * Don't call unnecessary expansions
- */
- if (strchr(map->src->name, '%') != NULL) {
- ssize_t slen;
- char *str = NULL;
+ ssize_t slen;
+ char *str;
- slen = radius_axlat(&str, request, map->src->name, NULL, NULL);
- if (slen < 0) {
- rcode = slen;
- goto error;
- }
- rcode = pairparsevalue(vp, str);
- talloc_free(str);
- if (!rcode) {
- pairfree(&vp);
- rcode = -1;
- goto error;
- }
+ case VPT_TYPE_XLAT_STRUCT:
+ rad_assert(map->dst->vpt_da); /* Need to know where were going to write the new attribute */
+ rad_assert(map->src->vpt_xlat != NULL);
- break;
+ str = NULL;
+ slen = radius_axlat_struct(&str, request, map->src->vpt_xlat, NULL, NULL);
+ if (slen < 0) {
+ rcode = slen;
+ goto error;
}
- /* FALL-THROUGH */
- case VPT_TYPE_LITERAL:
- if (!pairparsevalue(vp, map->src->name)) {
- rcode = -2;
+ /*
+ * We do the debug printing because radius_axlat_struct
+ * doesn't have access to the original string. It's been
+ * mangled during the parsing to xlat_exp_t
+ */
+ RDEBUG2("EXPAND %s", map->src->name);
+ RDEBUG2(" --> %s", str);
+
+ rcode = pairparsevalue(vp, str, 0);
+ talloc_free(str);
+ if (rcode < 0) {
+ pairfree(&vp);
goto error;
}
break;
- case VPT_TYPE_ATTR:
- rad_assert(!map->dst->da ||
- (map->src->da->type == map->dst->da->type) ||
- (map->src->da->type == PW_TYPE_OCTETS) ||
- (map->dst->da->type == PW_TYPE_OCTETS));
- context = request;
-
- if (radius_request(&context, map->src->request) == 0) {
- from = radius_list(context, map->src->list);
+ case VPT_TYPE_XLAT:
+ rad_assert(map->dst->vpt_da); /* Need to know where were going to write the new attribute */
+
+ str = NULL;
+ slen = radius_axlat(&str, request, map->src->name, NULL, NULL);
+ if (slen < 0) {
+ rcode = slen;
+ goto error;
}
+ rcode = pairparsevalue(vp, str, 0);
+ talloc_free(str);
+ if (rcode < 0) {
+ pairfree(&vp);
+ goto error;
+ }
+ break;
- /*
- * Can't add the attribute if the list isn't
- * valid.
- */
- if (!from) {
- rcode = -2;
+ case VPT_TYPE_LITERAL:
+ if (pairparsevalue(vp, map->src->name, 0) < 0) {
+ rcode = 0;
goto error;
}
+ break;
+
+ case VPT_TYPE_ATTR:
+ rad_assert(!map->dst->vpt_da ||
+ (map->src->vpt_da->type == map->dst->vpt_da->type) ||
+ (map->src->vpt_da->type == PW_TYPE_OCTETS) ||
+ (map->dst->vpt_da->type == PW_TYPE_OCTETS));
/*
* Special case, destination is a list, found all instance of an attribute.
*/
if (map->dst->type == VPT_TYPE_LIST) {
- found = paircopy2(request, *from, map->src->da->attr, map->src->da->vendor, TAG_ANY);
+ context = request;
+
+ if (radius_request(&context, map->src->vpt_request) == 0) {
+ from = radius_list(context, map->src->vpt_list);
+ }
+
+ /*
+ * Can't add the attribute if the list isn't
+ * valid.
+ */
+ if (!from) {
+ rcode = 0;
+ goto error;
+ }
+
+ found = paircopy2(request, *from, map->src->vpt_da->attr, map->src->vpt_da->vendor,
+ map->src->vpt_tag);
if (!found) {
REDEBUG("Attribute \"%s\" not found in request", map->src->name);
- rcode = -2;
+ rcode = 0;
goto error;
}
- for (vp = paircursor(&cursor, &found);
+ for (vp = fr_cursor_init(&cursor, &found);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
vp->op = T_OP_ADD;
}
return 0;
}
- /*
- * FIXME: allow tag references?
- */
- found = pairfind(*from, map->src->da->attr, map->src->da->vendor, TAG_ANY);
- if (!found) {
+ if (radius_tmpl_get_vp(&found, request, map->src) < 0) {
REDEBUG("Attribute \"%s\" not found in request", map->src->name);
- rcode = -2;
+ rcode = 0;
goto error;
}
* Copy the data over verbatim, assuming it's
* actually data.
*/
-// rad_assert(found->type == VT_DATA);
vp = paircopyvpdata(request, da, found);
if (!vp) {
return -1;
break;
case VPT_TYPE_DATA:
- rad_assert(map->src->da->type == map->dst->da->type);
- memcpy(&vp->data, map->src->vpd, sizeof(vp->data));
- vp->length = map->src->length;
+ rad_assert(map->src && map->src->vpt_da);
+ rad_assert(map->dst && map->dst->vpt_da);
+ rad_assert(map->src->vpt_da->type == map->dst->vpt_da->type);
+ memcpy(&vp->data, map->src->vpt_value, sizeof(vp->data));
+ vp->length = map->src->vpt_length;
break;
/*
case VPT_TYPE_EXEC:
return radius_mapexec(out, request, map);
default:
- rad_assert(0); /* Should of been caught at parse time */
+ rad_assert(0); /* Should have been caught at parse time */
error:
pairfree(&vp);
return rcode;
return 0;
}
-
-/** Convert a valuepair string to VALUE_PAIR and insert it into a list
+/** Convert a valuepair string to valuepair map
*
- * Takes a valuepair string with list and request qualifiers, converts it into a VALUE_PAIR
- * and inserts it into the appropriate list.
+ * Takes a valuepair string with list and request qualifiers, converts it into a
+ * value_pair_map_t and inserts it into the appropriate list.
*
+ * @param out Where to write the new map (must be freed with talloc_free()).
* @param request Current request.
* @param raw string to parse.
* @param dst_request_def to use if attribute isn't qualified.
* @param src_list_def to use if attribute isn't qualified.
* @return 0 on success, < 0 on error.
*/
-int radius_str2vp(REQUEST *request, char const *raw,
- request_refs_t dst_request_def, pair_lists_t dst_list_def,
- request_refs_t src_request_def, pair_lists_t src_list_def)
+int radius_strpair2map(value_pair_map_t **out, REQUEST *request, char const *raw,
+ request_refs_t dst_request_def, pair_lists_t dst_list_def,
+ request_refs_t src_request_def, pair_lists_t src_list_def)
{
char const *p = raw;
FR_TOKEN ret;
- int rcode;
VALUE_PAIR_RAW tokens;
value_pair_map_t *map;
}
map = radius_str2map(request, tokens.l_opand, T_BARE_WORD, tokens.op, tokens.r_opand, tokens.quote,
- dst_request_def, dst_list_def, src_request_def, src_list_def);
+ dst_request_def, dst_list_def, src_request_def, src_list_def);
if (!map) {
REDEBUG("Failed parsing attribute string: %s", fr_strerror());
return -1;
}
+ *out = map;
- rcode = radius_map2request(request, map, NULL, radius_map2vp, NULL);
- talloc_free(map);
- return rcode;
+ return 0;
}
+/** Check whether the destination of a map is currently valid
+ *
+ * @param request The current request.
+ * @param map to check.
+ * @return true if the map resolves to a request and list else false.
+ */
+bool radius_map_dst_valid(REQUEST *request, value_pair_map_t const *map)
+{
+ REQUEST *context = request;
+
+ if (radius_request(&context, map->dst->vpt_request) < 0) return false;
+ if (!radius_list(context, map->dst->vpt_list)) return false;
+
+ return true;
+}
/** Return a VP from a value_pair_tmpl_t
*
+ * @param out where to write the retrieved vp.
* @param request current request.
* @param vpt the value pair template
- * @return NULL if not found, or the VPs.
+ * @return -1 if VP could not be found, -2 if list could not be found, -3 if context could not be found.
*/
-VALUE_PAIR *radius_vpt_get_vp(REQUEST *request, value_pair_tmpl_t const *vpt)
+int radius_tmpl_get_vp(VALUE_PAIR **out, REQUEST *request, value_pair_tmpl_t const *vpt)
{
- VALUE_PAIR **vps;
+ VALUE_PAIR **vps, *vp;
- if (radius_request(&request, vpt->request) < 0) {
- return NULL;
+ if (out) *out = NULL;
+
+ if (radius_request(&request, vpt->vpt_request) < 0) {
+ return -3;
}
- vps = radius_list(request, vpt->list);
+ vps = radius_list(request, vpt->vpt_list);
if (!vps) {
- return NULL;
+ return -2;
}
switch (vpt->type) {
- /*
- * May not may not be found, but it *is* a known name.
- */
+ /*
+ * May not may not be found, but it *is* a known
+ * name.
+ */
case VPT_TYPE_ATTR:
- return pairfind(*vps, vpt->da->attr, vpt->da->vendor, TAG_ANY);
+ {
+ int num;
+ vp_cursor_t cursor;
+
+ if (vpt->vpt_num == NUM_ANY) {
+ vp = pairfind(*vps, vpt->vpt_da->attr, vpt->vpt_da->vendor, vpt->vpt_tag);
+ if (!vp) return -1;
+ break;
+ }
+
+ (void) fr_cursor_init(&cursor, vps);
+ num = vpt->vpt_num;
+ while((vp = fr_cursor_next_by_da(&cursor, vpt->vpt_da, vpt->vpt_tag))) {
+ VERIFY_VP(vp);
+ if (num-- == 0) goto finish;
+ }
+ return -1;
+ }
case VPT_TYPE_LIST:
- return *vps;
+ vp = *vps;
+ break;
default:
- break;
+ /*
+ * literal, xlat, regex, exec, data.
+ * no attribute.
+ */
+ return -1;
}
- return NULL;
-}
-
+finish:
+ if (out) *out = vp;
+ return 0;
+}
/** Return a VP from the specified request.
*
- * @param vp_p where to write the pointer to the resolved VP.
+ * @param out where to write the pointer to the resolved VP.
* Will be NULL if the attribute couldn't be resolved.
* @param request current request.
* @param name attribute name including qualifiers.
- * @return -1 if either the attribute or qualifier were invalid, else 0
+ * @return -4 if either the attribute or qualifier were invalid, and the same error codes as radius_tmpl_get_vp for other
+ * error conditions.
*/
-int radius_get_vp(VALUE_PAIR **vp_p, REQUEST *request, char const *name)
+int radius_get_vp(VALUE_PAIR **out, REQUEST *request, char const *name)
{
value_pair_tmpl_t vpt;
- *vp_p = NULL;
+ *out = NULL;
+
+ if (radius_parse_attr(&vpt, name, REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
+ return -4;
+ }
- if (radius_parse_attr(name, &vpt, REQUEST_CURRENT,
- PAIR_LIST_REQUEST) < 0) {
+ return radius_tmpl_get_vp(out, request, &vpt);
+}
+
+/** Copy pairs matching a VPT in the current request
+ *
+ * @param out where to write the copied vps.
+ * @param request current request.
+ * @param vpt the value pair template
+ * @return -1 if VP could not be found, -2 if list could not be found, -3 if context could not be found.
+ */
+int radius_tmpl_copy_vp(VALUE_PAIR **out, REQUEST *request, value_pair_tmpl_t const *vpt)
+{
+ VALUE_PAIR **vps, *vp;
+ REQUEST *current = request;
+
+ if (out) *out = NULL;
+
+ if (radius_request(¤t, vpt->vpt_request) < 0) {
+ return -3;
+ }
+
+ vps = radius_list(request, vpt->vpt_list);
+ if (!vps) {
+ return -2;
+ }
+
+ switch (vpt->type) {
+ /*
+ * May not may not be found, but it *is* a known name.
+ */
+ case VPT_TYPE_ATTR:
+ vp = paircopy2(request, *vps, vpt->vpt_da->attr, vpt->vpt_da->vendor, vpt->vpt_tag);
+ if (!vp) {
+ return -1;
+ }
+ break;
+
+ case VPT_TYPE_LIST:
+ vp = paircopy(request, *vps);
+
+ break;
+
+ default:
+ /*
+ * literal, xlat, regex, exec, data.
+ * no attribute.
+ */
return -1;
}
- *vp_p = radius_vpt_get_vp(request, &vpt);
+ if (out) {
+ *out = vp;
+ }
+
return 0;
}
-/** Add a module failure message VALUE_PAIR to the request
+/** Copy a VP from the specified request.
+ *
+ * @param out where to write the pointer to the copied VP.
+ * Will be NULL if the attribute couldn't be resolved.
+ * @param request current request.
+ * @param name attribute name including qualifiers.
+ * @return -4 if either the attribute or qualifier were invalid, and the same error codes as radius_tmpl_get_vp for other
+ * error conditions.
*/
+int radius_copy_vp(VALUE_PAIR **out, REQUEST *request, char const *name)
+{
+ value_pair_tmpl_t vpt;
+
+ *out = NULL;
+
+ if (radius_parse_attr(&vpt, name, REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
+ return -4;
+ }
+
+ return radius_tmpl_copy_vp(out, request, &vpt);
+}
+
void module_failure_msg(REQUEST *request, char const *fmt, ...)
{
va_list ap;
+
+ va_start(ap, fmt);
+ vmodule_failure_msg(request, fmt, ap);
+ va_end(ap);
+}
+
+/** Add a module failure message VALUE_PAIR to the request
+ */
+void vmodule_failure_msg(REQUEST *request, char const *fmt, va_list ap)
+{
char *p;
VALUE_PAIR *vp;
+ va_list aq;
if (!fmt || !request->packet) {
- va_start(ap, fmt);
- va_end(ap);
return;
}
- va_start(ap, fmt);
- vp = paircreate(request->packet, PW_MODULE_FAILURE_MESSAGE, 0);
- if (!vp) {
- va_end(ap);
- return;
- }
-
- p = talloc_vasprintf(vp, fmt, ap);
+ /*
+ * If we don't copy the original ap we get a segfault from vasprintf. This is apparently
+ * due to ap sometimes being implemented with a stack offset which is invalidated if
+ * ap is passed into another function. See here:
+ * http://julipedia.meroh.net/2011/09/using-vacopy-to-safely-pass-ap.html
+ *
+ * I don't buy that explanation, but doing a va_copy here does prevent SEGVs seen when
+ * running unit tests which generate errors under CI.
+ */
+ va_copy(aq, ap);
+ p = talloc_vasprintf(request, fmt, aq);
+ va_end(aq);
- if (request->module && *request->module) {
+ MEM(vp = pairmake_packet("Module-Failure-Message", NULL, T_OP_ADD));
+ if (request->module && (request->module[0] != '\0')) {
pairsprintf(vp, "%s: %s", request->module, p);
} else {
pairsprintf(vp, "%s", p);
}
talloc_free(p);
- pairadd(&request->packet->vps, vp);
}
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
- * Copyright 1999-2012 The FreeRADIUS server project
+ * Copyright 1999-2014 The FreeRADIUS server project
* Copyright 2012 Alan DeKok <aland@ox.org>
* Copyright 2000 Chris Parker <cparker@starnetusa.com>
*/
#include <freeradius-devel/radiusd.h>
USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
-#ifdef HAVE_OPENSSL_CRYPTO_H
+static uint64_t libmagic = RADIUSD_MAGIC_NUMBER;
-#include <openssl/crypto.h>
-#include <openssl/opensslv.h>
+#ifdef HAVE_OPENSSL_CRYPTO_H
+# include <openssl/crypto.h>
+# include <openssl/opensslv.h>
static long ssl_built = OPENSSL_VERSION_NUMBER;
*
* @return 0 if ok, else -1
*/
-int ssl_check_version(void)
+int ssl_check_consistency(void)
{
long ssl_linked;
ssl_linked = SSLeay();
if (ssl_linked != ssl_built) {
- ERROR("libssl version mismatch."
- " Built with: %lx\n Linked: %lx",
+ ERROR("libssl version mismatch. built: %lx linked: %lx",
(unsigned long) ssl_built,
(unsigned long) ssl_linked);
return 0;
}
+/** Convert a version number to a text string
+ *
+ * @note Not thread safe.
+ *
+ * @param v version to convert.
+ * @return pointer to a static buffer containing the version string.
+ */
+char const *ssl_version_by_num(uint64_t v)
+{
+ /* 2 (%s) + 1 (.) + 2 (%i) + 1 (.) + 2 (%i) + 1 (c) + 1 (-) + 2 (%i) + \0 */
+ static char buffer[13];
+ char *p = buffer;
+
+ p += sprintf(p, "%i.%i.%i",
+ (int) ((0xff0000000 & v) >> 28),
+ (int) ((0x00ff00000 & v) >> 20),
+ (int) ((0x0000ff000 & v) >> 12));
+
+ if ((0x000000ff0 & v) >> 4) {
+ *p++ = (char) (0x60 + ((0x000000ff0 & v) >> 4));
+ }
+
+ sprintf(p, "-%i", (int) (0x00000000f & v));
+
+ return buffer;
+}
+
+/** Convert two openssl version numbers into a range string
+ *
+ * @note Not thread safe.
+ *
+ * @param low version to convert.
+ * @param high version to convert.
+ * @return pointer to a static buffer containing the version range string.
+ */
+char const *ssl_version_range(uint64_t low, uint64_t high)
+{
+ /* 12 (version) + 3 ( - ) + 12 (version) */
+ static char buffer[28];
+ char *p = buffer;
+
+ p += strlcpy(p, ssl_version_by_num(low), sizeof(buffer));
+ p += strlcpy(p, " - ", sizeof(buffer) - (p - buffer));
+ strlcpy(p, ssl_version_by_num(high), sizeof(buffer) - (p - buffer));
+
+ return buffer;
+}
+
/** Print the current linked version of Openssl
*
* Print the currently linked version of the OpenSSL library.
+ *
+ * @note Not thread safe.
+ * @return pointer to a static buffer containing libssl version information.
*/
char const *ssl_version(void)
{
- return SSLeay_version(SSLEAY_VERSION);
+ static char buffer[256];
+
+ uint64_t v = (uint64_t) SSLeay();
+
+ snprintf(buffer, sizeof(buffer), "%s 0x%.9" PRIx64 " (%s)",
+ SSLeay_version(SSLEAY_VERSION), /* Not all builds include a useful version number */
+ v,
+ ssl_version_by_num((uint64_t) v));
+
+ return buffer;
}
-#else
-int ssl_check_version(void) {
+# else
+int ssl_check_consistency(void) {
return 0;
}
{
return "not linked";
}
-#endif
+#endif /* ifdef HAVE_OPENSSL_CRYPTO_H */
+
+
+/** Check if the application linking to the library has the correct magic number
+ *
+ * @param magic number as defined by RADIUSD_MAGIC_NUMBER
+ * @returns 0 on success, -1 on prefix mismatch, -2 on version mismatch -3 on commit mismatch.
+ */
+int rad_check_lib_magic(uint64_t magic)
+{
+ if (MAGIC_PREFIX(magic) != MAGIC_PREFIX(libmagic)) {
+ ERROR("Application and libfreeradius-server magic number (prefix) mismatch."
+ " application: %x library: %x",
+ MAGIC_PREFIX(magic), MAGIC_PREFIX(libmagic));
+ return -1;
+ }
+
+ if (MAGIC_VERSION(magic) != MAGIC_VERSION(libmagic)) {
+ ERROR("Application and libfreeradius-server magic number (version) mismatch."
+ " application: %lx library: %lx",
+ (unsigned long) MAGIC_VERSION(magic), (unsigned long) MAGIC_VERSION(libmagic));
+ return -2;
+ }
+
+ if (MAGIC_COMMIT(magic) != MAGIC_COMMIT(libmagic)) {
+ ERROR("Application and libfreeradius-server magic number (commit) mismatch."
+ " application: %lx library: %lx",
+ (unsigned long) MAGIC_COMMIT(magic), (unsigned long) MAGIC_COMMIT(libmagic));
+ return -3;
+ }
+
+ return 0;
+}
/*
* Display the revision number for this program
#ifdef WITH_VMPS
DEBUG3(" vmps");
#endif
+#ifndef NDEBUG
+ DEBUG3(" developer");
+#endif
DEBUG3("Server core libs:");
- DEBUG3(" talloc : %i.%i.*", talloc_version_major(),
- talloc_version_minor());
+ DEBUG3(" talloc : %i.%i.*", talloc_version_major(), talloc_version_minor());
DEBUG3(" ssl : %s", ssl_version());
+ DEBUG3("Library magic number:");
+ DEBUG3(" 0x%llx", (unsigned long long) libmagic);
+
+ DEBUG3("Endianess:");
+#if defined(LITTLE_ENDIAN)
+ DEBUG3(" little");
+#elif defined(BIG_ENDIAN)
+ DEBUG3(" big");
+#else
+ DEBUG3(" unknown");
+#endif
+
INFO("Copyright (C) 1999-2014 The FreeRADIUS server project and contributors");
INFO("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A");
INFO("PARTICULAR PURPOSE");
#include <freeradius-devel/base64.h>
#include <ctype.h>
-#include <limits.h>
-
typedef struct xlat_t {
char name[MAX_STRING_LEN]; //!< Name of the xlat expansion.
int length; //!< Length of name.
void *instance; //!< Module instance passed to xlat and escape functions.
RAD_XLAT_FUNC func; //!< xlat function.
RADIUS_ESCAPE_STRING escape; //!< Escape function to apply to dynamic input to func.
- int internal; //!< If true, cannot be redefined.
+ bool internal; //!< If true, cannot be redefined.
} xlat_t;
typedef enum {
size_t len; //!< Length of the format string.
DICT_ATTR const *da; //!< the name of the dictionary attribute
+
int num; //!< attribute number
- int tag; //!< attribute tag
+ int8_t tag; //!< attribute tag
pair_lists_t list; //!< list of which attribute
request_refs_t ref; //!< outer / this / ...
#endif
static int xlat_inst[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; /* up to 8 for regex */
+char const *radiusd_short_version = RADIUSD_VERSION_STRING;
-#ifdef WITH_UNLANG
-/** Convert the value on a VALUE_PAIR to string
+/** Print length of its RHS.
*
*/
-static int valuepair2str(char * out,int outlen,VALUE_PAIR * pair, int type)
+static ssize_t xlat_strlen(UNUSED void *instance, UNUSED REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
{
- if (pair != NULL) {
- vp_prints_value(out, outlen, pair, -1);
- return strlen(out);
- }
-
- switch (type) {
- case PW_TYPE_STRING :
- strlcpy(out,"_",outlen);
- break;
- case PW_TYPE_INTEGER64:
- case PW_TYPE_SIGNED:
- case PW_TYPE_INTEGER:
- strlcpy(out,"0",outlen);
- break;
- case PW_TYPE_IPADDR :
- strlcpy(out,"?.?.?.?",outlen);
- break;
- case PW_TYPE_IPV6ADDR :
- strlcpy(out,":?:",outlen);
- break;
- case PW_TYPE_DATE :
- strlcpy(out,"0",outlen);
- break;
- default :
- strlcpy(out,"unknown_type",outlen);
- }
+ snprintf(out, outlen, "%u", (unsigned int) strlen(fmt));
return strlen(out);
}
-#endif
-/** Print length of its RHS.
+/** Print the size of the attribute in bytes.
*
*/
-static ssize_t xlat_strlen(UNUSED void *instance, UNUSED REQUEST *request,
+static ssize_t xlat_length(UNUSED void *instance, UNUSED REQUEST *request,
char const *fmt, char *out, size_t outlen)
{
- snprintf(out, outlen, "%u", (unsigned int) strlen(fmt));
+ VALUE_PAIR *vp;
+ while (isspace((int) *fmt)) fmt++;
+
+ if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
+ *out = '\0';
+ return 0;
+ }
+
+ snprintf(out, outlen, "%zu", vp->length);
return strlen(out);
}
{
VALUE_PAIR *vp;
- uint64_t integer;
+ uint64_t int64 = 0; /* Needs to be initialised to zero */
+ uint32_t int32 = 0; /* Needs to be initialised to zero */
while (isspace((int) *fmt)) fmt++;
break;
}
- memcpy(&integer, &(vp->vp_octets), vp->length);
+ if (vp->length > 4) {
+ memcpy(&int64, vp->vp_octets, vp->length);
+ return snprintf(out, outlen, "%" PRIu64, htonll(int64));
+ }
- return snprintf(out, outlen, "%" PRIu64, ntohll(integer));
+ memcpy(&int32, vp->vp_octets, vp->length);
+ return snprintf(out, outlen, "%i", htonl(int32));
case PW_TYPE_INTEGER64:
return snprintf(out, outlen, "%" PRIu64, vp->vp_integer64);
- case PW_TYPE_IPADDR:
+ /*
+ * IP addresses are treated specially, as parsing functions assume the value
+ * is bigendian and will convert it for us.
+ */
+ case PW_TYPE_IPV4_ADDR:
+ return snprintf(out, outlen, "%u", htonl(vp->vp_ipaddr));
+
+ case PW_TYPE_IPV4_PREFIX:
+ return snprintf(out, outlen, "%u", htonl((*(uint32_t *)(vp->vp_ipv4prefix + 2))));
+
case PW_TYPE_INTEGER:
- case PW_TYPE_SHORT:
- case PW_TYPE_BYTE:
case PW_TYPE_DATE:
+ case PW_TYPE_BYTE:
+ case PW_TYPE_SHORT:
return snprintf(out, outlen, "%u", vp->vp_integer);
+
+ /*
+ * Ethernet is weird... It's network related, so we assume to it should be
+ * bigendian.
+ */
+ case PW_TYPE_ETHERNET:
+ memcpy(&int64, &vp->vp_ether, vp->length);
+ return snprintf(out, outlen, "%" PRIu64, htonll(int64));
+
+ case PW_TYPE_SIGNED:
+ return snprintf(out, outlen, "%i", vp->vp_signed);
+
+ case PW_TYPE_IPV6_ADDR:
+ return fr_prints_uint128(out, outlen, ntohlll(*(uint128_t const *) &vp->vp_ipv6addr));
+
+ case PW_TYPE_IPV6_PREFIX:
+ return fr_prints_uint128(out, outlen, ntohlll(*(uint128_t const *) &(vp->vp_ipv6prefix[2])));
+
default:
break;
}
- REDEBUG("Type \"%s\" cannot be converted to integer",
- fr_int2str(dict_attr_types, vp->da->type, PW_TYPE_INVALID));
+ REDEBUG("Type '%s' of length %zu cannot be converted to integer",
+ fr_int2str(dict_attr_types, vp->da->type, "???"), vp->length);
*out = '\0';
return -1;
*
*/
static ssize_t xlat_hex(UNUSED void *instance, REQUEST *request,
- char const *fmt, char *out, size_t outlen)
+ char const *fmt, char *out, size_t outlen)
{
size_t i;
VALUE_PAIR *vp;
- uint8_t buffer[MAX_STRING_LEN];
+ uint8_t const *p;
ssize_t ret;
size_t len;
return -1;
}
- ret = rad_vp2data(vp, buffer, sizeof(buffer));
+ ret = rad_vp2data(&p, vp);
+ if (ret < 0) {
+ return ret;
+ }
len = (size_t) ret;
/*
}
for (i = 0; i < len; i++) {
- snprintf(out + 2*i, 3, "%02x", buffer[i]);
+ snprintf(out + 2*i, 3, "%02x", p[i]);
}
return len * 2;
}
-/** Print data as base64, not as VALUE
+/** Return the tag of an attribute reference
*
*/
-static ssize_t xlat_base64(UNUSED void *instance, REQUEST *request,
- char const *fmt, char *out, size_t outlen)
+static ssize_t xlat_tag(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
{
VALUE_PAIR *vp;
- uint8_t buffer[MAX_STRING_LEN];
- ssize_t ret;
while (isspace((int) *fmt)) fmt++;
return 0;
}
- ret = rad_vp2data(vp, buffer, sizeof(buffer));
- if (ret < 0) {
+ if (!vp->da->flags.has_tag || !TAG_VALID(vp->tag)) {
*out = '\0';
- return ret;
+ return 0;
}
- return fr_base64_encode(buffer, (size_t) ret, out, outlen);
+ return snprintf(out, outlen, "%u", vp->tag);
}
/** Print out attribute info
while (isspace((int) *fmt)) fmt++;
- if (*fmt == '&') fmt++;
-
- if (radius_parse_attr(fmt, &vpt, REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
+ if (radius_parse_attr(&vpt, fmt, REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
+ RDEBUG("%s", fr_strerror());
return -1;
}
current = request;
- if (radius_request(¤t, vpt.request) < 0) return -2;
+ if (radius_request(¤t, vpt.vpt_request) < 0) return -2;
- vps = radius_list(current, vpt.list);
+ vps = radius_list(current, vpt.vpt_list);
if (!vps) {
return -2;
}
RIDEBUG("Attributes matching \"%s\"", fmt);
- vp = paircursor(&cursor, vps);
+ vp = fr_cursor_init(&cursor, vps);
- if (vpt.da) {
- vp = pairfindnext(&cursor, vpt.da->attr, vpt.da->vendor, TAG_ANY);
+ if (vpt.vpt_da) {
+ vp = fr_cursor_next_by_da(&cursor, vpt.vpt_da, TAG_ANY);
}
while (vp) {
DICT_ATTR *dac = NULL;
if (vp->da->flags.has_tag) {
RIDEBUG2("\t%s:%s:%i %s %s",
- fr_int2str(pair_lists, vpt.list, "<INVALID>"),
+ fr_int2str(pair_lists, vpt.vpt_list, "<INVALID>"),
vp->da->name,
vp->tag,
fr_int2str(fr_tokens, vp->op, "<INVALID>"),
buffer);
} else {
RIDEBUG2("\t%s:%s %s %s",
- fr_int2str(pair_lists, vpt.list, "<INVALID>"),
+ fr_int2str(pair_lists, vpt.vpt_list, "<INVALID>"),
vp->da->name,
fr_int2str(fr_tokens, vp->op, "<INVALID>"),
buffer);
RDEBUG3("\t\tlength : %zu", vp->length);
dac = talloc_memdup(request, vp->da, sizeof(DICT_ATTR));
- if (!dac) {
- return -1;
- }
+ if (!dac) return -1;
+ talloc_set_type(dac, DICT_ATTR);
dac->flags.vp_free = 0;
next_vp:
-
talloc_free(dac);
- if (vpt.da) {
- vp = pairfindnext(&cursor, vpt.da->attr, vpt.da->vendor, TAG_ANY);
+ if (vpt.vpt_da) {
+ vp = fr_cursor_next_by_da(&cursor, vpt.vpt_da, TAG_ANY);
} else {
- vp = pairnext(&cursor);
+ vp = fr_cursor_next(&cursor);
}
}
UNUSED char const *fmt, char *out, size_t outlen)
{
VALUE_PAIR **pvp;
+ size_t len;
/*
* See modcall, "FOREACH" for how this works.
return 0;
}
- return valuepair2str(out, outlen, (*pvp), (*pvp)->da->type);
+ len = vp_prints_value(out, outlen, *pvp, 0);
+ if (is_truncated(len, outlen)) {
+ RDEBUG("Insufficient buffer space to write foreach value");
+ return -1;
+ }
+
+ return len;
}
#endif
static ssize_t xlat_string(UNUSED void *instance, REQUEST *request,
char const *fmt, char *out, size_t outlen)
{
- int len;
+ size_t len;
+ ssize_t ret;
VALUE_PAIR *vp;
+ uint8_t const *p;
while (isspace((int) *fmt)) fmt++;
if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) goto nothing;
- if (vp->da->type != PW_TYPE_OCTETS) goto nothing;
+ ret = rad_vp2data(&p, vp);
+ if (ret < 0) {
+ return ret;
+ }
- len = fr_print_string(vp->vp_strvalue, vp->length, out, outlen);
- out[len] = '\0';
+ switch (vp->da->type) {
+ case PW_TYPE_OCTETS:
+ len = fr_print_string((char const *) p, vp->length, out, outlen);
+ break;
+
+ case PW_TYPE_STRING:
+ len = strlcpy(out, vp->vp_strvalue, outlen);
+ break;
+
+ default:
+ len = fr_print_string((char const *) p, ret, out, outlen);
+ break;
+ }
return len;
}
/*
* Expand to previous (or current) level
*/
- snprintf(out, outlen, "%d", request->options & RAD_REQUEST_OPTION_DEBUG4);
+ snprintf(out, outlen, "%d", request->log.lvl & RAD_REQUEST_OPTION_DEBUG4);
/*
* Assume we just want to get the current value and NOT set it to 0
level = atoi(fmt);
if (level == 0) {
- request->options = RAD_REQUEST_OPTION_NONE;
- request->radlog = NULL;
+ request->log.lvl = RAD_REQUEST_OPTION_NONE;
+ request->log.func = NULL;
} else {
if (level > 4) level = 4;
- request->options = level;
- request->radlog = radlog_request;
+ request->log.lvl = level;
+ request->log.func = vradlog_request;
}
done:
*/
int xlat_register(char const *name, RAD_XLAT_FUNC func, RADIUS_ESCAPE_STRING escape, void *instance)
{
- xlat_t *c;
- xlat_t my_xlat;
+ xlat_t *c;
+ xlat_t my_xlat;
+ rbnode_t *node;
if (!name || !*name) {
DEBUG("xlat_register: Invalid xlat name");
xlat_root = rbtree_create(xlat_cmp, free, 0);
if (!xlat_root) {
- DEBUG("xlat_register: Failed to create tree.");
+ DEBUG("xlat_register: Failed to create tree");
return -1;
}
XLAT_REGISTER(integer);
XLAT_REGISTER(strlen);
+ XLAT_REGISTER(length);
XLAT_REGISTER(hex);
- XLAT_REGISTER(base64);
+ XLAT_REGISTER(tag);
XLAT_REGISTER(string);
XLAT_REGISTER(xlat);
XLAT_REGISTER(module);
c->length = strlen(c->name);
c->instance = instance;
- rbtree_insert(xlat_root, c);
+ node = rbtree_insert_node(xlat_root, c);
+ if (!node) {
+ talloc_free(c);
+ return -1;
+ }
return 0;
}
rbtree_deletebydata(xlat_root, c);
}
+
+/** Crappy temporary function to add attribute ref support to xlats
+ *
+ * This needs to die, and hopefully will die, when xlat functions accept
+ * xlat node structures.
+ *
+ * Provides either a pointer to a buffer which contains the value of the reference VALUE_PAIR
+ * in an architecture independent format. Or a pointer to the start of the fmt string.
+ *
+ * The pointer is only guaranteed to be valid between calls to xlat_fmt_to_ref,
+ * and so long as the source VALUE_PAIR is not freed.
+ *
+ * @param out where to write a pointer to the buffer to the data the xlat function needs to work on.
+ * @param request current request.
+ * @param fmt string.
+ * @returns the length of the data or -1 on error.
+ */
+ssize_t xlat_fmt_to_ref(uint8_t const **out, REQUEST *request, char const *fmt)
+{
+ VALUE_PAIR *vp;
+
+ while (isspace((int) *fmt)) fmt++;
+
+ if (fmt[0] == '&') {
+ if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
+ *out = NULL;
+ return -1;
+ }
+
+ return rad_vp2data(out, vp);
+ }
+
+ *out = (uint8_t const *)fmt;
+ return strlen(fmt);
+}
+
/** De-register all xlat functions, used mainly for debugging.
*
*/
rbtree_free(xlat_root);
}
-#if 0
-#define XLAT_DEBUG(fmt, ...) printf(fmt, ## __VA_ARGS__);printf("\n")
-#endif
-#ifndef XLAT_DEBUG
-#if 0
+#ifdef DEBUG_XLAT
#define XLAT_DEBUG DEBUG3
#else
#define XLAT_DEBUG(...)
#endif
-#endif
static ssize_t xlat_tokenize_expansion(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
char const **error);
rad_assert(fmt[2] == '%');
rad_assert(fmt[3] == '{');
- XLAT_DEBUG("ALTERNATE: %s", fmt);
+ XLAT_DEBUG("ALTERNATE <-- %s", fmt);
node = talloc_zero(ctx, xlat_exp_t);
node->type = XLAT_ALTERNATE;
*/
node->alternate = talloc_zero(node, xlat_exp_t);
node->alternate->type = XLAT_LITERAL;
- node->alternate->fmt = talloc_strdup(node->alternate, "");
+ node->alternate->fmt = talloc_typed_strdup(node->alternate, "");
*(p++) = '\0';
} else {
return xlat_tokenize_alternation(ctx, fmt, head, error);
}
- XLAT_DEBUG("EXPANSION: %s", fmt);
+ XLAT_DEBUG("EXPANSION <-- %s", fmt);
node = talloc_zero(ctx, xlat_exp_t);
attrname = node->fmt = fmt + 2;
node->len = 0;
return -2;
}
- XLAT_DEBUG("REGEX: %s", fmt);
+ XLAT_DEBUG("REGEX <-- %s", fmt);
fmt[3] = '\0';
node->num = fmt[2] - '0'; /* ASCII */
* %{request:Tunnel-Password:1[#]}
* %{mod:foo}
*/
- q = brace = NULL;
+ brace = NULL;
for (p = fmt + 2; *p != '\0'; p++) {
if (*p == ':') break;
if (node->xlat) {
node->type = XLAT_MODULE;
- XLAT_DEBUG("MOD: %s --> %s", node->fmt, p);
+ XLAT_DEBUG("MOD <-- %s ... %s", node->fmt, p + 1);
+
slen = xlat_tokenize_literal(node, p + 1, &node->child, true, error);
if (slen <= 0) {
talloc_free(node);
node->type = XLAT_VIRTUAL;
node->fmt = attrname;
- XLAT_DEBUG("VIRTUAL: %s", node->fmt);
+ XLAT_DEBUG("VIRTUAL <-- %s", node->fmt);
*head = node;
rad_assert(node->next == NULL);
brace++;
p = q;
if (*p== '#') {
- node->num = 65536;
+ node->num = NUM_COUNT;
p++;
} else if (*p == '*') {
- node->num = 65537;
+ node->num = NUM_JOIN;
p++;
} else if (isdigit((int) *p)) {
num = strtoul(p, &end, 10);
- if ((num == ULONG_MAX) || (num > 65535)) {
+ if (num > 1000) {
talloc_free(node);
- *error = "Invalid number";
+ *error = "Invalid array reference";
return - (p - fmt);
}
p = end;
*error = "Unexpected text after array reference";
return - (p - fmt);
}
+ } else {
+ node->num = NUM_ANY;
}
rad_assert(!p || (p == brace));
if (!*fmt) return 0;
- XLAT_DEBUG("LITERAL: %s", fmt);
+ XLAT_DEBUG("LITERAL <-- %s", fmt);
node = talloc_zero(ctx, xlat_exp_t);
node->fmt = fmt;
if ((p[0] == '%') && (p[1] == '{')) {
ssize_t slen;
- XLAT_DEBUG("LITERAL: %s --> %s", node->fmt, p);
+ XLAT_DEBUG("LITERAL <-- %s", node->fmt);
+
slen = xlat_tokenize_expansion(node, p, &node->next, error);
if (slen <= 0) {
talloc_free(node);
ssize_t slen;
xlat_exp_t *next;
- if (!p[1] || !strchr("%dlmtDGHISTY", p[1])) {
+ if (!p[1] || !strchr("%dlmtDGHISTYv", p[1])) {
talloc_free(node);
*error = "Invalid variable expansion";
p++;
return - (p - fmt);
}
- XLAT_DEBUG("PERCENT: %s --> %c", node->fmt, p[1]);
next = talloc_zero(node, xlat_exp_t);
- next->fmt = p + 1;
next->len = 1;
- next->type = XLAT_PERCENT;
+
+ if (p[1] == '%') {
+ next->fmt = talloc_typed_strdup(next, "%");
+
+ XLAT_DEBUG("LITERAL <-- %s", next->fmt);
+ next->type = XLAT_LITERAL;
+
+ } else {
+ next->fmt = p + 1;
+
+ XLAT_DEBUG("PERCENT <-- %c", *next->fmt);
+ next->type = XLAT_PERCENT;
+ }
node->next = next;
*p = '\0';
while (node) {
switch (node->type) {
case XLAT_LITERAL:
- DEBUG("%.*sliteral: '%s'", lvl, xlat_tabs, node->fmt);
+ DEBUG("%.*sliteral --> %s", lvl, xlat_tabs, node->fmt);
break;
case XLAT_PERCENT:
- DEBUG("%.*sliteral (with %%): '%c'", lvl, xlat_tabs, node->fmt[0]);
+ DEBUG("%.*spercent --> %c", lvl, xlat_tabs, node->fmt[0]);
break;
case XLAT_ATTRIBUTE:
rad_assert(node->da != NULL);
- DEBUG("%.*sattribute: %s", lvl, xlat_tabs, node->da->name);
+ DEBUG("%.*sattribute --> %s", lvl, xlat_tabs, node->da->name);
rad_assert(node->child == NULL);
- if ((node->tag != 0) || (node->num != 0)) {
+ if ((node->tag != TAG_ANY) || (node->num != NUM_ANY)) {
DEBUG("%.*s{", lvl, xlat_tabs);
DEBUG("%.*sref %d", lvl + 1, xlat_tabs, node->ref);
DEBUG("%.*slist %d", lvl + 1, xlat_tabs, node->list);
- if (node->tag) DEBUG("%.*stag %d", lvl + 1, xlat_tabs, node->tag);
- if (node->num) {
- if (node->num == 65536) {
+ if (node->tag != TAG_ANY) {
+ DEBUG("%.*stag %d", lvl + 1, xlat_tabs, node->tag);
+ }
+ if (node->num != NUM_ANY) {
+ if (node->num == NUM_COUNT) {
DEBUG("%.*s[#]", lvl + 1, xlat_tabs);
- } else if (node->num == 65537) {
+ } else if (node->num == NUM_JOIN) {
DEBUG("%.*s[*]", lvl + 1, xlat_tabs);
} else {
DEBUG("%.*s[%d]", lvl + 1, xlat_tabs, node->num);
case XLAT_VIRTUAL:
rad_assert(node->fmt != NULL);
- DEBUG("%.*svirtual: %s", lvl, xlat_tabs, node->fmt);
+ DEBUG("%.*svirtual --> %s", lvl, xlat_tabs, node->fmt);
break;
case XLAT_MODULE:
rad_assert(node->xlat != NULL);
- DEBUG("%.*sxlat: %s", lvl, xlat_tabs, node->xlat->name);
+ DEBUG("%.*sxlat --> %s", lvl, xlat_tabs, node->xlat->name);
if (node->child) {
DEBUG("%.*s{", lvl, xlat_tabs);
xlat_tokenize_debug(node->child, lvl + 1);
#ifdef HAVE_REGEX_H
case XLAT_REGEX:
- DEBUG("%.*sregex-var: %d", lvl, xlat_tabs, node->num);
+ DEBUG("%.*sregex-var --> %d", lvl, xlat_tabs, node->num);
break;
#endif
p += strlen(p);
}
- if (node->num != 0) {
+ if (node->num != NUM_ANY) {
*(p++) = '[';
-
- if (node->num == 65536) {
+ switch (node->num) {
+ case NUM_COUNT:
*(p++) = '#';
+ break;
- } else if (node->num == 65537) {
+ case NUM_JOIN:
*(p++) = '*';
+ break;
- } else {
+ default:
snprintf(p, end - p, "%u", node->num);
p += strlen(p);
}
return p - buffer;
}
-
-static char const xlat_spaces[] = " ";
-
-
ssize_t xlat_tokenize(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
char const **error)
{
* the later functions can mangle it in-place, which is
* much faster.
*/
- tokens = talloc_strdup(request, fmt);
+ tokens = talloc_typed_strdup(request, fmt);
if (!tokens) return -1;
slen = xlat_tokenize_literal(request, tokens, head, false, &error);
+
/*
* Zero length expansion, return a zero length node.
*/
* " ^ error was here"
*/
if (slen < 0) {
- size_t indent = -slen;
talloc_free(tokens);
-
rad_assert(error != NULL);
- if (indent < sizeof(xlat_spaces)) {
- REDEBUG("%s", fmt);
- REDEBUG("%.*s^ %s", (int) -slen, xlat_spaces, error);
- }
+
+ REMARKER(fmt, -slen, error);
return slen;
}
}
-static char *xlat_getvp(TALLOC_CTX *ctx, REQUEST *request, pair_lists_t list, DICT_ATTR const *da, int8_t tag,
- int num, bool return_null)
+static char *xlat_getvp(TALLOC_CTX *ctx, REQUEST *request, pair_lists_t list, DICT_ATTR const *da,
+ int8_t tag, int num, bool return_null)
{
- VALUE_PAIR *vp, *vps = NULL;
+ VALUE_PAIR *vp, *vps = NULL, *myvp = NULL;
RADIUS_PACKET *packet = NULL;
DICT_VALUE *dv;
- VALUE_PAIR myvp;
+ char *ret = NULL;
/*
* Arg. Too much abstraction is annoying.
switch (list) {
default:
if (return_null) return NULL;
- return vp_aprinttype(ctx, da->type);
+ return vp_aprint_type(ctx, da->type);
case PAIR_LIST_CONTROL:
vps = request->config_items;
}
/*
- * Now that we have the list, etc. handled,
- * find the VP and print it.
+ * Now we have the list, check to see if we have an attribute in
+ * the request, if we do, it takes precedence over the virtual
+ * attributes.
+ *
+ * This allows users to manipulate virtual attributes as if they
+ * were real ones.
*/
- if ((da->vendor != 0) || (da->attr < 256) || (list == PAIR_LIST_CONTROL)) {
- print_vp:
- vp = pairfind(vps, da->attr, da->vendor, tag);
- if (!vp) {
- return NULL;
- }
- goto do_print;
- }
+ vp = pairfind(vps, da->attr, da->vendor, tag);
+ if (vp) goto do_print;
/*
* Some non-packet expansions
break; /* ignore them */
case PW_CLIENT_SHORTNAME:
+ if (num == NUM_COUNT) goto count;
if (request->client && request->client->shortname) {
- return talloc_strdup(ctx, request->client->shortname);
+ return talloc_typed_strdup(ctx, request->client->shortname);
}
- return talloc_strdup(ctx, "<UNKNOWN-CLIENT>");
+ return talloc_typed_strdup(ctx, "<UNKNOWN-CLIENT>");
case PW_REQUEST_PROCESSING_STAGE:
+ if (num == NUM_COUNT) goto count;
if (request->component) {
- return talloc_strdup(ctx, request->component);
+ return talloc_typed_strdup(ctx, request->component);
}
- return talloc_strdup(ctx, "server_core");
+ return talloc_typed_strdup(ctx, "server_core");
case PW_VIRTUAL_SERVER:
+ if (num == NUM_COUNT) goto count;
if (!request->server) return NULL;
- return talloc_strdup(ctx, request->server);
+ return talloc_typed_strdup(ctx, request->server);
case PW_MODULE_RETURN_CODE:
- return talloc_asprintf(ctx, "%d", request->simul_max); /* hack */
+ if (num == NUM_COUNT) goto count;
+ if (!request->rcode) return NULL;
+ return talloc_typed_strdup(ctx, fr_int2str(modreturn_table, request->rcode, ""));
}
/*
- * All of the attributes must now refer to a packet. If
- * there's no packet, we can't print any attribute
+ * All of the attributes must now refer to a packet.
+ * If there's no packet, we can't print any attribute
* referencing it.
*/
if (!packet) {
if (return_null) return NULL;
- return vp_aprinttype(ctx, da->type);
+ return vp_aprint_type(ctx, da->type);
}
- memset(&myvp, 0, sizeof(myvp));
- myvp.da = da;
vp = NULL;
-
switch (da->attr) {
default:
- goto print_vp;
+ break;
case PW_PACKET_TYPE:
dv = dict_valbyattr(PW_PACKET_TYPE, 0, packet->code);
- if (dv) return talloc_strdup(ctx, dv->name);
- return talloc_asprintf(ctx, "%d", packet->code);
+ if (dv) return talloc_typed_strdup(ctx, dv->name);
+ return talloc_typed_asprintf(ctx, "%d", packet->code);
case PW_RESPONSE_PACKET_TYPE:
{
code = request->reply->code;
}
- return talloc_strdup(ctx, fr_packet_codes[code]);
+ return talloc_typed_strdup(ctx, fr_packet_codes[code]);
}
+ /*
+ * Virtual attributes which require a temporary VALUE_PAIR
+ * to be allocated. We can't use stack allocated memory
+ * because of the talloc checks sprinkled throughout the
+ * various VP functions.
+ */
case PW_PACKET_AUTHENTICATION_VECTOR:
- myvp.length = sizeof(packet->vector);
- memcpy(&myvp.vp_octets, packet->vector, sizeof(packet->vector));
- vp = &myvp;
+ myvp = pairalloc(ctx, da);
+ pairmemcpy(myvp, packet->vector, sizeof(packet->vector));
+ vp = myvp;
break;
case PW_CLIENT_IP_ADDRESS:
case PW_PACKET_SRC_IP_ADDRESS:
if (packet->src_ipaddr.af == AF_INET) {
- myvp.vp_ipaddr = packet->src_ipaddr.ipaddr.ip4addr.s_addr;
- vp = &myvp;
+ myvp = pairalloc(ctx, da);
+ myvp->vp_ipaddr = packet->src_ipaddr.ipaddr.ip4addr.s_addr;
+ vp = myvp;
}
break;
case PW_PACKET_DST_IP_ADDRESS:
if (packet->dst_ipaddr.af == AF_INET) {
- myvp.vp_ipaddr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr;
- vp = &myvp;
+ myvp = pairalloc(ctx, da);
+ myvp->vp_ipaddr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr;
+ vp = myvp;
}
break;
case PW_PACKET_SRC_IPV6_ADDRESS:
if (packet->src_ipaddr.af == AF_INET6) {
- memcpy(&myvp.vp_ipv6addr,
+ myvp = pairalloc(ctx, da);
+ memcpy(&myvp->vp_ipv6addr,
&packet->src_ipaddr.ipaddr.ip6addr,
sizeof(packet->src_ipaddr.ipaddr.ip6addr));
- vp = &myvp;
+ vp = myvp;
}
break;
case PW_PACKET_DST_IPV6_ADDRESS:
if (packet->dst_ipaddr.af == AF_INET6) {
- memcpy(&myvp.vp_ipv6addr,
+ myvp = pairalloc(ctx, da);
+ memcpy(&myvp->vp_ipv6addr,
&packet->dst_ipaddr.ipaddr.ip6addr,
sizeof(packet->dst_ipaddr.ipaddr.ip6addr));
- vp = &myvp;
+ vp = myvp;
}
break;
case PW_PACKET_SRC_PORT:
- myvp.vp_integer = packet->src_port;
- vp = &myvp;
+ myvp = pairalloc(ctx, da);
+ myvp->vp_integer = packet->src_port;
+ vp = myvp;
break;
case PW_PACKET_DST_PORT:
- myvp.vp_integer = packet->dst_port;
- vp = &myvp;
+ myvp = pairalloc(ctx, da);
+ myvp->vp_integer = packet->dst_port;
+ vp = myvp;
break;
}
-do_print:
/*
- * Hack up the virtual attributes.
+ * Fake various operations for virtual attributes.
*/
- if (num && (vp == &myvp)) {
- char *p, *q;
-
+ if (myvp) {
+ if (num != NUM_ANY) switch (num) {
+ /*
+ * [n] is NULL (we only have [0])
+ */
+ default:
+ goto finish;
/*
* [*] means only one.
*/
- if (num == 65537) num = 0;
+ case NUM_JOIN:
+ break;
/*
- * [n] means NULL, as there's only one.
+ * [#] means 1 (as there's only one)
*/
- if ((num > 0) && (num < 65536)) {
- return NULL;
- }
-
- p = vp_aprint(ctx, vp);
- rad_assert(p != NULL);
+ case NUM_COUNT:
+ count:
+ ret = talloc_strdup(ctx, "1");
+ goto finish;
/*
- * Get the length of it.
+ * [0] is fine (get the first instance)
*/
- if (num == 65536) {
- q = talloc_asprintf(ctx, "%d", (int) strlen(p));
- talloc_free(p);
- return q;
+ case 0:
+ break;
}
-
- return p;
+ goto print;
}
+do_print:
/*
* We want the N'th VP.
*/
- if (num) {
+ if (num != NUM_ANY) {
int count = 0;
vp_cursor_t cursor;
+ switch (num) {
/*
* Return a count of the VPs.
*/
- if (num == 65536) {
- paircursor(&cursor, &vp);
- while (pairfindnext(&cursor, da->attr, da->vendor, tag) != NULL) {
+ case NUM_COUNT:
+ fr_cursor_init(&cursor, &vp);
+ while (fr_cursor_next_by_da(&cursor, da, tag) != NULL) {
count++;
}
-
- return talloc_asprintf(ctx, "%d", count);
- }
+ return talloc_typed_asprintf(ctx, "%d", count);
/*
* Ugly, but working.
*/
- if (num == 65537) {
+ case NUM_JOIN:
+ {
char *p, *q;
- vp = paircursor(&cursor, &vp);
- vp = pairfindnext(&cursor, da->attr, da->vendor, tag);
+ (void) fr_cursor_init(&cursor, &vp);
+ vp = fr_cursor_next_by_da(&cursor, da, tag);
if (!vp) return NULL;
- p = vp_aprint(ctx, vp);
- while ((vp = pairfindnext(&cursor, da->attr, da->vendor, tag)) != NULL) {
- q = vp_aprint(ctx, vp);
+
+ p = vp_aprint_value(ctx, vp);
+ if (!p) return NULL;
+ while ((vp = fr_cursor_next_by_da(&cursor, da, tag)) != NULL) {
+ q = vp_aprint_value(ctx, vp);
+ if (!q) return NULL;
p = talloc_strdup_append(p, ",");
p = talloc_strdup_append(p, q);
}
return p;
}
- paircursor(&cursor, &vp);
- while (pairfindnext(&cursor, da->attr, da->vendor, tag) != NULL) {
- if (count == num) {
- break;
+ default:
+ fr_cursor_init(&cursor, &vp);
+ while ((vp = fr_cursor_next_by_da(&cursor, da, tag)) != NULL) {
+ if (count++ == num) break;
}
- count++;
+ break;
}
}
if (!vp) {
if (return_null) return NULL;
- return vp_aprinttype(ctx, da->type);
+ return vp_aprint_type(ctx, da->type);
}
- return vp_aprint(ctx, vp);
+print:
+ ret = vp_aprint_value(ctx, vp);
+
+finish:
+ talloc_free(myvp);
+ return ret;
}
+#ifdef DEBUG_XLAT
+static const char *xlat_spaces = " ";
+#endif
+
static char *xlat_aprint(TALLOC_CTX *ctx, REQUEST *request, xlat_exp_t const * const node,
RADIUS_ESCAPE_STRING escape, void *escape_ctx, int lvl)
{
*/
case XLAT_LITERAL:
XLAT_DEBUG("xlat_aprint LITERAL");
- return talloc_strdup(ctx, node->fmt);
+ return talloc_typed_strdup(ctx, node->fmt);
/*
* Do a one-character expansion.
strftime(str, freespace, "%m", &ts);
break;
+ case 'n': /* Request Number*/
+ snprintf(str, freespace, "%i", request->number);
+ break;
+
case 't': /* request timestamp */
CTIME_R(&when, str, freespace);
nl = strchr(str, '\n');
strftime(str, freespace, "%Y", &ts);
break;
+ case 'v': /* Version of code */
+ snprintf(str, freespace, "%s", radiusd_short_version);
+ break;
+
default:
rad_assert(0 == 1);
break;
*/
str = xlat_getvp(ctx, ref, node->list, node->da, node->tag, node->num, true);
if (str) {
- XLAT_DEBUG("expand attr %s --> '%s'", node->da->name, str);
+ XLAT_DEBUG("EXPAND attr %s", node->da->name);
+ XLAT_DEBUG(" ---> %s", str);
}
break;
case XLAT_VIRTUAL:
XLAT_DEBUG("xlat_aprint VIRTUAL");
- str = talloc_array(ctx, char, 1024); /* FIXME: have the module call talloc_asprintf */
+ str = talloc_array(ctx, char, 1024); /* FIXME: have the module call talloc_typed_asprintf */
rcode = node->xlat->func(node->xlat->instance, request, NULL, str, 1024);
if (rcode < 0) {
talloc_free(str);
return NULL;
}
- XLAT_DEBUG("%.*sexpand mod %s --> '%s'", lvl, xlat_spaces, node->fmt, child);
+ XLAT_DEBUG("%.*sEXPAND mod %s %s", lvl, xlat_spaces, node->fmt, node->child->fmt);
+ XLAT_DEBUG("%.*s ---> %s", lvl, xlat_spaces, child);
- str = talloc_array(ctx, char, 1024); /* FIXME: have the module call talloc_asprintf */
+ str = talloc_array(ctx, char, 1024); /* FIXME: have the module call talloc_typed_asprintf */
*str = '\0'; /* Be sure the string is NULL terminated, we now only free on error */
rcode = node->xlat->func(node->xlat->instance, request, child, str, 1024);
REQUEST_DATA_REGEX | node->num);
if (!child) return NULL;
- str = talloc_strdup(ctx, child);
+ str = talloc_typed_strdup(ctx, child);
break;
#endif
* @param[out] out Where to write pointer to output buffer.
* @param[in] outlen Size of out.
* @param[in] request current request.
- * @param[in] fmt string to expand.
+ * @param[in] node the xlat structure to expand
* @param[in] escape function to escape final value e.g. SQL quoting.
* @param[in] escape_ctx pointer to pass to escape function.
* @return length of string written @bug should really have -1 for failure
*/
-static ssize_t xlat_expand(char **out, size_t outlen, REQUEST *request, char const *fmt,
- RADIUS_ESCAPE_STRING escape, void *escape_ctx)
+static ssize_t xlat_expand_struct(char **out, size_t outlen, REQUEST *request, xlat_exp_t const *node,
+ RADIUS_ESCAPE_STRING escape, void *escape_ctx)
{
char *buff;
ssize_t len;
- xlat_exp_t *node;
- rad_assert(fmt);
- rad_assert(request);
+ rad_assert(node != NULL);
+
+ len = xlat_process(&buff, request, node, escape, escape_ctx);
+
+ if ((len < 0) || !buff) {
+ rad_assert(buff == NULL);
+ if (*out) *out[0] = '\0';
+ return len;
+ }
+
+ if (!*out) {
+ *out = buff;
+ } else {
+ strlcpy(*out, buff, outlen);
+ talloc_free(buff);
+ }
+
+ return strlen(*out);
+}
+
+static ssize_t xlat_expand(char **out, size_t outlen, REQUEST *request, char const *fmt,
+ RADIUS_ESCAPE_STRING escape, void *escape_ctx) CC_HINT(nonnull (1, 3, 4));
+
+/** Replace %whatever in a string.
+ *
+ * See 'doc/variables.txt' for more information.
+ *
+ * @param[out] out Where to write pointer to output buffer.
+ * @param[in] outlen Size of out.
+ * @param[in] request current request.
+ * @param[in] fmt string to expand.
+ * @param[in] escape function to escape final value e.g. SQL quoting.
+ * @param[in] escape_ctx pointer to pass to escape function.
+ * @return length of string written @bug should really have -1 for failure
+ */
+static ssize_t CC_HINT(nonnull (1, 3, 4)) xlat_expand(char **out, size_t outlen, REQUEST *request, char const *fmt,
+ RADIUS_ESCAPE_STRING escape, void *escape_ctx)
+{
+ ssize_t len;
+ xlat_exp_t *node;
/*
* Give better errors than the old code.
return -1;
}
- len = xlat_process(&buff, request, node, escape, escape_ctx);
+ len = xlat_expand_struct(out, outlen, request, node, escape, escape_ctx);
talloc_free(node);
- if ((len < 0) || !buff) {
- rad_assert(buff == NULL);
- if (*out) *out[0] = '\0';
- return len;
- }
+ RDEBUG2("EXPAND %s", fmt);
+ RDEBUG2(" --> %s", *out);
- RDEBUG2("\texpand: \"%s\" -> '%s'", fmt, buff);
+ return len;
+}
- if (!*out) {
- *out = buff;
- } else {
- strlcpy(*out, buff, outlen);
- }
+/*
+ * Try to convert an xlat to a tmpl for efficiency
+ */
+value_pair_tmpl_t *radius_xlat2tmpl(TALLOC_CTX *ctx, xlat_exp_t *xlat)
+{
+ value_pair_tmpl_t *vpt;
- return strlen(*out);
+ if (xlat->next || (xlat->type != XLAT_ATTRIBUTE)) return NULL;
+
+ /*
+ * @todo it should be possible to emulate the concat and count operations in the
+ * map code.
+ */
+ if ((xlat->num == NUM_COUNT) || (xlat->num == NUM_JOIN)) return NULL;
+
+ vpt = talloc(ctx, value_pair_tmpl_t);
+ if (!vpt) return NULL;
+
+ vpt->type = VPT_TYPE_ATTR;
+ vpt->name = talloc_strdup(vpt, xlat->fmt);
+ vpt->vpt_request = xlat->ref;
+ vpt->vpt_list = xlat->list;
+ vpt->vpt_da = xlat->da;
+ vpt->vpt_num = xlat->num;
+ vpt->vpt_tag = xlat->tag;
+
+ return vpt;
}
ssize_t radius_xlat(char *out, size_t outlen, REQUEST *request, char const *fmt, RADIUS_ESCAPE_STRING escape, void *ctx)
{
return xlat_expand(out, 0, request, fmt, escape, ctx);
}
+
+ssize_t radius_axlat_struct(char **out, REQUEST *request, xlat_exp_t const *xlat, RADIUS_ESCAPE_STRING escape, void *ctx)
+{
+ return xlat_expand_struct(out, 0, request, xlat, escape, ctx);
+}
esac
if test ! -d "$pathcomp"; then
- echo "mkdir $pathcomp"
+ echo "mkdir $pathcomp"
- mkdir "$pathcomp" || lasterr=$?
+ mkdir "$pathcomp" || lasterr=$?
- if test ! -d "$pathcomp"; then
- errstatus=$lasterr
- fi
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ fi
fi
pathcomp="$pathcomp/"
/* @todo: this is a hack */
# define DEBUG if (fr_debug_flag && fr_log_fp) fr_printf_log
-void fr_strerror_printf(char const *fmt, ...);
# define debug_pair(vp) do { if (fr_debug_flag && fr_log_fp) { \
vp_print(fr_log_fp, vp); \
} \
socklen_t sizeof_src;
socklen_t sizeof_dst;
RADIUS_PACKET *packet;
- int port;
+ uint16_t port;
uint8_t *code;
ssize_t data_len;
#endif
if (data_len <= 0) {
- fr_strerror_printf("Failed reading DHCP socket: %s", strerror(errno));
+ fr_strerror_printf("Failed reading DHCP socket: %s", fr_syserror(errno));
rad_free(&packet);
return NULL;
}
packet->data_len = data_len;
if (packet->data_len < MIN_PACKET_SIZE) {
fr_strerror_printf("DHCP packet is too small (%zu < %d)",
- packet->data_len, MIN_PACKET_SIZE);
+ packet->data_len, MIN_PACKET_SIZE);
rad_free(&packet);
return NULL;
}
if (packet->data_len > MAX_PACKET_SIZE) {
fr_strerror_printf("DHCP packet is too large (%zx > %d)",
- packet->data_len, MAX_PACKET_SIZE);
+ packet->data_len, MAX_PACKET_SIZE);
rad_free(&packet);
return NULL;
}
* This should never fail...
*/
if (getsockname(sockfd, (struct sockaddr *) &dst, &sizeof_dst) < 0) {
- fr_strerror_printf("getsockname failed: %s", strerror(errno));
+ fr_strerror_printf("getsockname failed: %s", fr_syserror(errno));
rad_free(&packet);
return NULL;
}
packet->code - PW_DHCP_OFFSET);
}
- DEBUG("Received %s of id %08x from %s:%d to %s:%d\n",
+ DEBUG("Received %s of Id %08x from %s:%d to %s:%d\n",
name, (unsigned int) packet->id,
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
DEBUG(
#ifdef WITH_UDPFROMTO
- "Sending %s of id %08x from %s:%d to %s:%d\n",
+ "Sending %s Id %08x from %s:%d to %s:%d\n",
#else
- "Sending %s of id %08x to %s:%d\n",
+ "Sending %s Id %08x to %s:%d\n",
#endif
name, (unsigned int) packet->id,
#ifdef WITH_UDPFROMTO
* Got here... must be well formed.
*/
head = NULL;
- paircursor(&cursor, &head);
+ fr_cursor_init(&cursor, &head);
p = data;
while (p < (data + data_len)) {
goto make_tlv;
}
- pairinsert(&cursor, vp);
+ fr_cursor_insert(&cursor, vp);
p += 2 + p[1];
}
/*
* The caller allocated TLV, so we need to copy the FIRST
* attribute over top of that.
+ *
+ * This is a pretty awful hack, but we should be able to
+ * clean it up when we get nested VPs so lets leave it for
+ * now.
*/
if (head) {
+ /* Cleanup any old TLV data */
+ talloc_free(tlv->vp_tlv);
+
+ /* @fixme fragile */
memcpy(tlv, head, sizeof(*tlv));
- head->next = NULL;
- pairfree(&head);
+
+ /* If the VP has a talloced value we need to reparent it to the original TLV attribute */
+ switch (head->da->type) {
+ case PW_TYPE_STRING:
+ case PW_TYPE_OCTETS:
+ case PW_TYPE_TLV:
+ (void) talloc_steal(tlv, head->data.ptr);
+ default:
+ break;
+ }
+ tlv->next = head->next;
+ talloc_free(head);
}
return 0;
switch (vp->da->type) {
case PW_TYPE_BYTE:
if (alen != 1) goto raw;
- vp->vp_integer = p[0];
+ vp->vp_byte = p[0];
break;
case PW_TYPE_SHORT:
if (alen != 2) goto raw;
- memcpy(&vp->vp_integer, p, 2);
- vp->vp_integer = ntohs(vp->vp_integer);
+ memcpy(&vp->vp_short, p, 2);
+ vp->vp_short = ntohs(vp->vp_short);
break;
case PW_TYPE_INTEGER:
vp->vp_integer = ntohl(vp->vp_integer);
break;
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
if (alen != 4) goto raw;
/*
* Keep value in Network Order!
next = data;
*head = NULL;
- paircursor(&cursor, head);
+ fr_cursor_init(&cursor, head);
/*
* FIXME: This should also check sname && file fields.
alen = 2;
break;
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
case PW_TYPE_INTEGER:
case PW_TYPE_DATE: /* ignore any trailing data */
num_entries = alen >> 2;
return -1;
}
- pairinsert(&cursor, vp);
+ fr_cursor_insert(&cursor, vp);
- for (vp = paircurrent(&cursor);
+ for (vp = fr_cursor_current(&cursor);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
debug_pair(vp);
}
p += alen;
VALUE_PAIR *head = NULL, *vp;
VALUE_PAIR *maxms, *mtu;
- paircursor(&cursor, &head);
+ fr_cursor_init(&cursor, &head);
p = packet->data;
if ((fr_debug_flag > 2) && fr_log_fp) {
switch (vp->da->type) {
case PW_TYPE_BYTE:
- vp->vp_integer = p[0];
+ vp->vp_byte = p[0];
vp->length = 1;
break;
case PW_TYPE_SHORT:
- vp->vp_integer = (p[0] << 8) | p[1];
+ vp->vp_short = (p[0] << 8) | p[1];
vp->length = 2;
break;
vp->length = 4;
break;
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
memcpy(&vp->vp_ipaddr, p, 4);
vp->length = 4;
break;
if (!vp) continue;
debug_pair(vp);
- pairinsert(&cursor, vp);
+ fr_cursor_insert(&cursor, vp);
}
/*
}
if (options) {
- pairinsert(&cursor, options);
+ fr_cursor_insert(&cursor, options);
}
}
mtu = pairfind(packet->vps, 26, DHCP_MAGIC_VENDOR, TAG_ANY);
if (mtu && (mtu->vp_integer < DEFAULT_PACKET_SIZE)) {
- fr_strerror_printf("DHCP Fatal: Client says MTU is smaller than minimum permitted by the specification.");
+ fr_strerror_printf("DHCP Fatal: Client says MTU is smaller than minimum permitted by the specification");
return -1;
}
}
-static int attr_cmp(void const *one, void const *two)
+int8_t fr_dhcp_attr_cmp(void const *a, void const *b)
{
- VALUE_PAIR const * const *a = one;
- VALUE_PAIR const * const *b = two;
+ VALUE_PAIR const *my_a = a;
+ VALUE_PAIR const *my_b = b;
+
+ VERIFY_VP(my_a);
+ VERIFY_VP(my_b);
/*
* DHCP-Message-Type is first, for simplicity.
*/
- if (((*a)->da->attr == 53) &&
- (*b)->da->attr != 53) return -1;
+ if ((my_a->da->attr == 53) && (my_b->da->attr != 53)) return -1;
/*
* Relay-Agent is last
*/
- if (((*a)->da->attr == 82) &&
- (*b)->da->attr != 82) return 1;
+ if ((my_a->da->attr == 82) && (my_b->da->attr != 82)) return 1;
+
+ if (my_a->da->attr < my_b->da->attr) return -1;
+ if (my_a->da->attr > my_b->da->attr) return 1;
- return ((*a)->da->attr - (*b)->da->attr);
+ return 0;
}
-/*
- * @todo Check room!
+/** Write DHCP option value into buffer
+ *
+ * Does not include DHCP option length or number.
+ *
+ * @param out where to write the DHCP option.
+ * @param outlen length of output buffer.
+ * @param vp option to encode.
+ * @return the length of data writen, -1 if out of buffer, -2 if unsupported type.
*/
-static size_t fr_dhcp_vp2attr(VALUE_PAIR *vp, uint8_t *p, UNUSED size_t room)
+static ssize_t fr_dhcp_vp2attr(uint8_t *out, size_t outlen, VALUE_PAIR *vp)
{
- size_t length;
uint32_t lvalue;
+ uint8_t *p = out;
+
+ if (outlen < vp->length) {
+ return -1;
+ }
- /*
- * Search for all attributes of the same
- * type, and pack them into the same
- * attribute.
- */
switch (vp->da->type) {
case PW_TYPE_BYTE:
- length = 1;
- *p = vp->vp_integer & 0xff;
+ *p = vp->vp_byte;
break;
case PW_TYPE_SHORT:
- length = 2;
- p[0] = (vp->vp_integer >> 8) & 0xff;
- p[1] = vp->vp_integer & 0xff;
+ p[0] = (vp->vp_short >> 8) & 0xff;
+ p[1] = vp->vp_short & 0xff;
break;
case PW_TYPE_INTEGER:
- length = 4;
lvalue = htonl(vp->vp_integer);
memcpy(p, &lvalue, 4);
break;
- case PW_TYPE_IPADDR:
- length = 4;
+ case PW_TYPE_IPV4_ADDR:
memcpy(p, &vp->vp_ipaddr, 4);
break;
case PW_TYPE_ETHERNET:
- length = 6;
memcpy(p, &vp->vp_ether, 6);
break;
case PW_TYPE_STRING:
memcpy(p, vp->vp_strvalue, vp->length);
- length = vp->length;
break;
case PW_TYPE_TLV: /* FIXME: split it on 255? */
memcpy(p, vp->vp_tlv, vp->length);
- length = vp->length;
break;
case PW_TYPE_OCTETS:
memcpy(p, vp->vp_octets, vp->length);
- length = vp->length;
break;
default:
- fr_strerror_printf("BAD TYPE2 %d", vp->da->type);
- length = 0;
- break;
+ fr_strerror_printf("Unsupported option type %d", vp->da->type);
+ return -2;
}
- return length;
+ return vp->length;
}
-static VALUE_PAIR *fr_dhcp_vp2suboption(RADIUS_PACKET *packet, VALUE_PAIR *vps)
+/** Create a new TLV attribute from multiple sub options
+ *
+ * @param[in,out] ctx to allocate new attribute in.
+ * @param[in,out] cursor should be set to the start of the list of TLV attributes.
+ * Will be advanced to the first non-TLV attribute.
+ * @return attribute holding the concatenation of the values of the sub options.
+ */
+static VALUE_PAIR *fr_dhcp_vp2suboption(TALLOC_CTX *ctx, vp_cursor_t *cursor)
{
- int length;
- unsigned int attribute;
- uint8_t *ptr;
- vp_cursor_t cursor;
+ ssize_t length;
+ unsigned int parent; /* Parent attribute of suboption */
+ uint8_t attr = 0;
+ uint8_t *p, *opt_len = NULL;
+ vp_cursor_t to_pack;
VALUE_PAIR *vp, *tlv;
- attribute = vps->da->attr & 0xffff00ff;
+#define SUBOPTION_PARENT(_x) (_x & 0xffff00ff)
+#define SUBOPTION_ATTR(_x) ((_x & 0xff00) >> 8)
+
+ vp = fr_cursor_current(cursor);
+ if (!vp) return NULL;
- tlv = paircreate(packet, attribute, DHCP_MAGIC_VENDOR);
+ parent = SUBOPTION_PARENT(vp->da->attr);
+ tlv = paircreate(ctx, parent, DHCP_MAGIC_VENDOR);
if (!tlv) return NULL;
- tlv->length = 0;
- for (vp = paircursor(&cursor, &vps);
- vp;
- vp = pairnext(&cursor)) {
+ fr_cursor_copy(&to_pack, cursor);
+
+ /*
+ * Loop over TLVs to determine how much memory we need to allocate
+ *
+ * We advanced the cursor we were passed, so if we fail encoding,
+ * the cursor is at the right position for the next potentially
+ * encodable attr.
+ */
+ for (vp = fr_cursor_current(cursor);
+ vp && vp->da->flags.is_tlv && !vp->da->flags.extended && (SUBOPTION_PARENT(vp->da->attr) == parent);
+ vp = fr_cursor_next(cursor)) {
/*
- * Group the attributes ONLY until we see a
- * non-TLV attribute.
+ * If it's not an array type or is an array type, but is not the same
+ * as the previous attribute, we add 2 for the additional sub-option
+ * header bytes.
*/
- if (!vp->da->flags.is_tlv ||
- vp->da->flags.extended ||
- ((vp->da->attr & 0xffff00ff) != attribute)) {
- break;
+ if (!vp->da->flags.array || (SUBOPTION_ATTR(vp->da->attr) != attr)) {
+ attr = SUBOPTION_ATTR(vp->da->attr);
+ tlv->length += 2;
}
-
- tlv->length += vp->length + 2;
- }
-
- if (!tlv->length) {
- pairfree(&tlv);
- return NULL;
+ tlv->length += vp->length;
}
tlv->vp_tlv = talloc_array(tlv, uint8_t, tlv->length);
if (!tlv->vp_tlv) {
- pairfree(&tlv);
+ talloc_free(tlv);
return NULL;
}
+ p = tlv->vp_tlv;
+
+ attr = 0;
+ for (vp = fr_cursor_current(&to_pack);
+ vp && vp->da->flags.is_tlv && !vp->da->flags.extended && (SUBOPTION_PARENT(vp->da->attr) == parent);
+ vp = fr_cursor_next(&to_pack)) {
+ if (SUBOPTION_ATTR(vp->da->attr) == 0) {
+ fr_strerror_printf("Invalid attribute number 0");
+ return NULL;
+ }
- ptr = tlv->vp_tlv;
- for (vp = paircursor(&cursor, &vps);
- vp;
- vp = pairnext(&cursor)) {
- if (!vp->da->flags.is_tlv ||
- vp->da->flags.extended ||
- ((vp->da->attr & 0xffff00ff) != attribute)) {
- break;
+ /* Don't write out the header, were packing array options */
+ if (!vp->da->flags.array || (attr != SUBOPTION_ATTR(vp->da->attr))) {
+ attr = SUBOPTION_ATTR(vp->da->attr);
+ *p++ = attr;
+ opt_len = p++;
}
- length = fr_dhcp_vp2attr(vp, ptr + 2,
- tlv->vp_tlv + tlv->length - ptr);
- if (length > 255) {
- pairfree(&tlv);
+ length = fr_dhcp_vp2attr(p, (tlv->vp_tlv + tlv->length) - p, vp);
+ if ((length < 0) || (length > 255)) {
+ talloc_free(tlv);
return NULL;
}
+ fr_assert(opt_len);
+ *opt_len += length;
+ p += length;
+ };
+
+ return tlv;
+}
+
+/** Encode a DHCP option and any sub-options.
+ *
+ * @param out Where to write encoded DHCP attributes.
+ * @param outlen Length of out buffer.
+ * @param ctx to use for any allocated memory.
+ * @param cursor with current VP set to the option to be encoded. Will be advanced to the next option to encode.
+ * @return > 0 length of data written, < 0 error, 0 not valid option (skipping).
+ */
+ssize_t fr_dhcp_encode_option(uint8_t *out, size_t outlen, TALLOC_CTX *ctx, vp_cursor_t *cursor)
+{
+ VALUE_PAIR *vp;
+ DICT_ATTR const *previous;
+ uint8_t *opt_len, *p = out;
+ size_t freespace = outlen;
+ ssize_t len;
+
+ vp = fr_cursor_current(cursor);
+ if (!vp) return -1;
+
+ if (vp->da->vendor != DHCP_MAGIC_VENDOR) goto next; /* not a DHCP option */
+ if (vp->da->attr == 53) goto next; /* already done */
+ if ((vp->da->attr > 255) && (DHCP_BASE_ATTR(vp->da->attr) != PW_DHCP_OPTION_82)) goto next;
+
+ if (vp->da->flags.extended) {
+ next:
+ fr_strerror_printf("Attribute \"%s\" is not a DHCP option", vp->da->name);
+ fr_cursor_next(cursor);
+ return 0;
+ }
+
+ /* Write out the option number */
+ *(p++) = vp->da->attr & 0xff;
+
+ /* Pointer to the length field of the option */
+ opt_len = p++;
+
+ /* Zero out the option's length field */
+ *opt_len = 0;
+
+ /* We just consumed two bytes for the header */
+ freespace -= 2;
+
+ /* DHCP options with the same number get coalesced into a single option */
+ do {
+ VALUE_PAIR *tlv = NULL;
+
+ /* Sub option */
+ if (vp->da->flags.is_tlv) {
+ /*
+ * Coalesce TLVs into one sub-option.
+ * Cursor will be advanced to next non-TLV attribute.
+ */
+ tlv = vp = fr_dhcp_vp2suboption(ctx, cursor);
+
+ /*
+ * Skip if there's an issue coalescing the sub-options.
+ * Cursor will still have been advanced to next non-TLV attribute.
+ */
+ if (!tlv) return 0;
/*
- * Pack the attribute.
+ * If not calling fr_dhcp_vp2suboption() advance the cursor, so fr_cursor_current()
+ * returns the next attribute.
*/
- ptr[0] = (vp->da->attr & 0xff00) >> 8;
- ptr[1] = length;
+ } else {
+ fr_cursor_next(cursor);
+ }
- ptr += length + 2;
- }
+ if ((*opt_len + vp->length) > 255) {
+ fr_strerror_printf("Skipping \"%s\": Option splitting not supported "
+ "(option > 255 bytes)", vp->da->name);
+ talloc_free(tlv);
+ return 0;
+ }
- return tlv;
-}
+ len = fr_dhcp_vp2attr(p, freespace, vp);
+ talloc_free(tlv);
+ if (len < 0) {
+ /* Failed encoding option */
+ return len;
+ }
+ p += len;
+ *opt_len += len;
+ freespace -= len;
+
+ previous = vp->da;
+ } while ((vp = fr_cursor_current(cursor)) && (previous == vp->da) && vp->da->flags.array);
+
+ return p - out;
+}
int fr_dhcp_encode(RADIUS_PACKET *packet)
{
- unsigned int i, num_vps;
+ unsigned int i;
uint8_t *p;
vp_cursor_t cursor;
VALUE_PAIR *vp;
uint32_t lvalue;
- size_t dhcp_size, length;
+ size_t dhcp_size;
+ ssize_t len;
#ifndef NDEBUG
char const *name;
# ifdef WITH_UDPFROMTO
}
DEBUG(
-#ifdef WITH_UDPFROMTO
+# ifdef WITH_UDPFROMTO
"Encoding %s of id %08x from %s:%d to %s:%d\n",
-#else
+# else
"Encoding %s of id %08x to %s:%d\n",
-#endif
+# endif
name, (unsigned int) packet->id,
-#ifdef WITH_UDPFROMTO
+# ifdef WITH_UDPFROMTO
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
src_ip_buf, sizeof(src_ip_buf)),
packet->src_port,
-#endif
+# endif
inet_ntop(packet->dst_ipaddr.af,
&packet->dst_ipaddr.ipaddr,
dst_ip_buf, sizeof(dst_ip_buf)),
*/
/* DHCP-Boot-Filename */
- if ((vp = pairfind(packet->vps, 269, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ vp = pairfind(packet->vps, 269, DHCP_MAGIC_VENDOR, TAG_ANY);
+ if (vp) {
if (vp->length > DHCP_FILE_LEN) {
memcpy(p, vp->vp_strvalue, DHCP_FILE_LEN);
} else {
switch (vp->da->type) {
case PW_TYPE_BYTE:
- vp->vp_integer = p[0];
- vp->length = 1;
+ vp->vp_byte = p[0];
break;
case PW_TYPE_SHORT:
- vp->vp_integer = (p[0] << 8) | p[1];
- vp->length = 2;
+ vp->vp_short = (p[0] << 8) | p[1];
break;
case PW_TYPE_INTEGER:
memcpy(&vp->vp_integer, p, 4);
vp->vp_integer = ntohl(vp->vp_integer);
- vp->length = 4;
break;
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
memcpy(&vp->vp_ipaddr, p, 4);
- vp->length = 4;
break;
case PW_TYPE_STRING:
case PW_TYPE_ETHERNET: /* only for Client HW Address */
memcpy(vp->vp_ether, p, sizeof(vp->vp_ether));
- vp->length = sizeof(vp->vp_ether);
break;
default:
p = pp;
}
- /*
- * Before packing the attributes, re-order them so that
- * the array ones are all contiguous. This simplifies
- * the later code.
- */
- num_vps = 0;
- for (vp = paircursor(&cursor, &packet->vps);
- vp;
- vp = pairnext(&cursor)) {
- num_vps++;
- }
- if (num_vps > 1) {
- VALUE_PAIR **array;
-
- array = talloc_array(packet, VALUE_PAIR*, num_vps);
-
- i = 0;
- for (vp = paircursor(&cursor, &packet->vps);
- vp;
- vp = pairnext(&cursor)) {
- array[i++] = vp;
- }
-
- /*
- * Sort the attributes.
- */
- qsort(array, (size_t) num_vps, sizeof(VALUE_PAIR *), attr_cmp);
-
- packet->vps = NULL;
- paircursor(&cursor, &packet->vps);
- for (i = 0; i < num_vps; i++) {
- array[i]->next = NULL;
- pairinsert(&cursor, array[i]);
- }
- talloc_free(array);
- }
-
p[0] = 0x35; /* DHCP-Message-Type */
p[1] = 1;
p[2] = packet->code - PW_DHCP_OFFSET;
p += 3;
+
/*
- * Pack in the attributes.
+ * Pre-sort attributes into contiguous blocks so that fr_dhcp_encode_option
+ * operates correctly. This changes the order of the list, but never mind...
*/
- vp = packet->vps;
- while (vp) {
- unsigned int num_entries = 1;
- VALUE_PAIR *same;
- uint8_t *plength;
-
- if (vp->da->vendor != DHCP_MAGIC_VENDOR) goto next;
- if (vp->da->attr == 53) goto next; /* already done */
- if ((vp->da->attr > 255) &&
- (DHCP_BASE_ATTR(vp->da->attr) != PW_DHCP_OPTION_82)) goto next;
-
- debug_pair(vp);
- if (vp->da->flags.extended) goto next;
-
- for (same = paircursor(&cursor, &vp->next);
- same;
- same = pairnext(&cursor)) {
- if (same->da->attr != vp->da->attr) break;
- num_entries++;
- }
-
- /*
- * For client-identifier
- * @todo What's this meant to be doing?!
- */
-#if 0
- if ((vp->da->type == PW_TYPE_ETHERNET) &&
- (vp->length == 6) &&
- (num_entries == 1)) {
- vp->da->type = PW_TYPE_OCTETS;
- memmove(vp->vp_octets + 1, vp->vp_octets, 6);
- vp->vp_octets[0] = 1;
- }
-#endif
- *(p++) = vp->da->attr & 0xff;
- plength = p;
- *(p++) = 0; /* header isn't included in attr length */
-
- for (i = 0; i < num_entries; i++) {
- if (i != 0) debug_pair(vp);
-
- if (vp->da->flags.is_tlv) {
- VALUE_PAIR *tlv;
-
- /*
- * Should NOT have been encoded yet!
- */
- tlv = fr_dhcp_vp2suboption(packet, vp);
-
- /*
- * Ignore it if there's an issue
- * encoding it.
- */
- if (!tlv) goto next;
-
- tlv->next = vp->next;
- vp->next = tlv;
- vp = tlv;
- }
-
- length = fr_dhcp_vp2attr(vp, p, 0);
+ pairsort(&packet->vps, fr_dhcp_attr_cmp);
+ fr_cursor_init(&cursor, &packet->vps);
- /*
- * This will never happen due to FreeRADIUS
- * limitations: sizeof(vp->vp_octets) < 255
- */
- if (length > 255) {
- fr_strerror_printf("WARNING Ignoring too long attribute %s!", vp->da->name);
- break;
- }
-
- /*
- * More than one attribute of the same type
- * in a row: they are packed together
- * into the same TLV. If we overflow,
- * go bananas!
- */
- if ((*plength + length) > 255) {
- fr_strerror_printf("WARNING Ignoring too long attribute %s!", vp->da->name);
- break;
- }
-
- *plength += length;
- p += length;
-
- if (vp->next &&
- (vp->next->da->attr == vp->da->attr))
- vp = vp->next;
- } /* loop over num_entries */
-
- next:
- vp = vp->next;
- }
+ /*
+ * Each call to fr_dhcp_encode_option will encode one complete DHCP option,
+ * and sub options.
+ */
+ while ((vp = fr_cursor_current(&cursor))) {
+ len = fr_dhcp_encode_option(p, packet->data_len - (p - packet->data), packet, &cursor);
+ if (len < 0) break;
+ if (len > 0) debug_pair(vp);
+ p += len;
+ };
p[0] = 0xff; /* end of option option */
p[1] = 0x00;
if (!fr_assert(macaddr) ||
!fr_assert((macaddr->da->type == PW_TYPE_ETHERNET) || (macaddr->da->type == PW_TYPE_OCTETS))) {
- fr_strerror_printf("Wrong VP type (%s) for chaddr",
- fr_int2str(dict_attr_types, macaddr->da->type, "<invalid>"));
+ fr_strerror_printf("Wrong VP type (%s) for chaddr",
+ fr_int2str(dict_attr_types, macaddr->da->type, "<invalid>"));
return -1;
}
req.arp_flags = ATF_COM;
if (ioctl(fd, SIOCSARP, &req) < 0) {
- fr_strerror_printf("Failed to add entry in ARP cache: %s (%d)", strerror(errno), errno);
+ fr_strerror_printf("Failed to add entry in ARP cache: %s (%d)", fr_syserror(errno), errno);
return -1;
}
static int retries = 3;
static float timeout = 5;
-static int server_port = 0;
+static uint16_t server_port = 0;
static int packet_code = 0;
static fr_ipaddr_t server_ipaddr;
static fr_ipaddr_t client_ipaddr;
-static int client_port = 0;
+static uint16_t client_port = 0;
static int sockfd;
char const *dhcpclient_version = "dhcpclient version " RADIUSD_VERSION_STRING
#ifdef RADIUSD_VERSION_COMMIT
-" (git #" RADIUSD_VERSION_COMMIT ")"
+" (git #" STRINGIFY(RADIUSD_VERSION_COMMIT) ")"
#endif
", built on " __DATE__ " at " __TIME__;
FILE *fp;
vp_cursor_t cursor;
VALUE_PAIR *vp;
- int filedone = 0;
+ bool filedone = false;
/*
* Determine where to read the VP's from.
fp = fopen(filename, "r");
if (!fp) {
fprintf(stderr, "dhcpclient: Error opening %s: %s\n",
- filename, strerror(errno));
+ filename, fr_syserror(errno));
return 0;
}
} else {
/*
* Read the VP's.
*/
- request->vps = readvp2(NULL, fp, &filedone, "dhcpclient:");
- if (!request->vps) {
+ if (readvp2(&request->vps, NULL, fp, &filedone) < 0) {
+ fr_perror("dhcpclient");
rad_free(&request);
if (fp != stdin) fclose(fp);
return 1;
/*
* Fix / set various options
*/
- for (vp = paircursor(&cursor, &request->vps); vp; vp = pairnext(&cursor)) {
+ for (vp = fr_cursor_init(&cursor, &request->vps); vp; vp = fr_cursor_next(&cursor)) {
switch (vp->da->attr) {
default:
break;
portname = NULL;
}
- if (ip_hton(hostname, AF_INET, &server_ipaddr) < 0) {
- fprintf(stderr, "dhcpclient: Failed to find IP address for host %s: %s\n", hostname, strerror(errno));
+ if (ip_hton(&server_ipaddr, AF_INET, hostname, false) < 0) {
+ fprintf(stderr, "dhcpclient: Failed to find IP address for host %s: %s\n", hostname, fr_syserror(errno));
exit(1);
}
if (fr_dhcp_send(request) < 0) {
fprintf(stderr, "dhcpclient: failed sending: %s\n",
- strerror(errno));
+ fr_syserror(errno));
exit(1);
}
static int dhcprelay_process_client_request(REQUEST *request)
{
uint8_t maxhops = 16;
- VALUE_PAIR *vp, *giaddrvp;
+ VALUE_PAIR *vp, *giaddr;
dhcp_socket_t *sock;
rad_assert(request->packet->data[0] == 1);
/*
- * Do the forward by ourselves, do not rely on dhcp_socket_send()
+ * Do the forward by ourselves, do not rely on dhcp_socket_send()
*/
request->reply->code = 0;
/*
* It's invalid to have giaddr=0 AND a relay option
*/
- giaddrvp = vp = pairfind(request->packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
- if (vp && (vp->vp_ipaddr == htonl(INADDR_ANY)) &&
+ giaddr = pairfind(request->packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
+ if (giaddr && (giaddr->vp_ipaddr == htonl(INADDR_ANY)) &&
pairfind(request->packet->vps, 82, DHCP_MAGIC_VENDOR, TAG_ANY)) { /* DHCP-Relay-Agent-Information */
DEBUG("DHCP: Received packet with giaddr = 0 and containing relay option: Discarding packet\n");
return 1;
*/
/* set SRC ipaddr/port to the listener ipaddr/port */
request->packet->src_ipaddr.af = AF_INET;
- request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = giaddrvp->vp_ipaddr;
+ request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = sock->lsock.my_ipaddr.ipaddr.ip4addr.s_addr;
request->packet->src_port = sock->lsock.my_port;
vp = pairfind(request->config_items, 270, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Relay-To-IP-Address */
/* set DEST ipaddr/port to the next server ipaddr/port */
request->packet->dst_ipaddr.af = AF_INET;
request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ request->packet->dst_port = sock->lsock.my_port;
if (fr_dhcp_encode(request->packet) < 0) {
DEBUG("dhcprelay_process_client_request: ERROR in fr_dhcp_encode\n");
return fr_dhcp_send(request->packet);
}
+
+/*
+ * We've seen a reply from a server.
+ * i.e. we're a relay.
+ */
static int dhcprelay_process_server_reply(REQUEST *request)
{
- VALUE_PAIR *vp, *giaddrvp;
+ VALUE_PAIR *vp, *giaddr;
dhcp_socket_t *sock;
rad_assert(request->packet->data[0] == 2);
/*
* Check that packet is for us.
*/
- giaddrvp = vp = pairfind(request->packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
- rad_assert(vp != NULL);
+ giaddr = pairfind(request->packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
/* --with-udpfromto is needed just for the following test */
- if (!vp || vp->vp_ipaddr != request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr) {
+ if (!giaddr || giaddr->vp_ipaddr != request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr) {
DEBUG("DHCP: Packet received from server was not for us (was for 0x%x). Discarding packet",
ntohl(request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr));
return 1;
/* set SRC ipaddr/port to the listener ipaddr/port */
request->packet->src_ipaddr.af = AF_INET;
- request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = giaddrvp->vp_ipaddr;
request->packet->src_port = sock->lsock.my_port;
/* set DEST ipaddr/port to clientip/68 or broadcast in specific cases */
request->packet->dst_ipaddr.af = AF_INET;
- request->packet->dst_port = request->packet->dst_port + 1; /* Port 68 */
+
+ /*
+ * We're a relay, and send the reply to giaddr.
+ */
+ request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = giaddr->vp_ipaddr;
+ request->reply->dst_port = request->packet->dst_port; /* server port */
if ((request->packet->code == PW_DHCP_NAK) ||
!sock->src_interface ||
} else {
vp = pairfind(request->packet->vps, 264, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Your-IP-Address */
if (!vp) {
- DEBUG("DHCP: Failed to find IP Address for request.");
+ DEBUG("DHCP: Failed to find IP Address for request");
return -1;
}
#else /* WITH_UDPFROMTO */
static int dhcprelay_process_server_reply(UNUSED REQUEST *request)
{
- WDEBUG("DHCP Relaying requires the server to be configured with UDPFROMTO");
+ WARN("DHCP Relaying requires the server to be configured with UDPFROMTO");
return -1;
}
static int dhcprelay_process_client_request(UNUSED REQUEST *request)
{
- WDEBUG("DHCP Relaying requires the server to be configured with UDPFROMTO");
+ WARN("DHCP Relaying requires the server to be configured with UDPFROMTO");
return -1;
}
VALUE_PAIR *relay;
/* DHCP-Relay-IP-Address */
- relay = radius_paircreate(request, &request->reply->vps,
+ relay = radius_paircreate(request->reply, &request->reply->vps,
272, DHCP_MAGIC_VENDOR);
if (relay) relay->vp_ipaddr = vp->vp_ipaddr;
}
vp->vp_integer = 2; /* BOOTREPLY */
/*
- * Prepare the reply packet for sending through dhcp_socket_send()
+ * Allow NAKs to be delayed for a short period of time.
+ */
+ if (request->reply->code == PW_DHCP_NAK) {
+ vp = pairfind(request->reply->vps, PW_FREERADIUS_RESPONSE_DELAY, 0, TAG_ANY);
+ if (vp) {
+ if (vp->vp_integer <= 10) {
+ request->response_delay = vp->vp_integer;
+ } else {
+ request->response_delay = 10;
+ }
+ }
+ }
+
+ /*
+ * Prepare the reply packet for sending through dhcp_socket_send()
*/
request->reply->dst_ipaddr.af = AF_INET;
request->reply->src_ipaddr.af = AF_INET;
request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = sock->src_ipaddr.ipaddr.ip4addr.s_addr;
+ /*
+ * They didn't set a proper src_ipaddr, but we want to
+ * send the packet with a source IP. If there's a server
+ * identifier, use it.
+ */
+ if (request->reply->src_ipaddr.ipaddr.ip4addr.s_addr == INADDR_ANY) {
+ vp = pairfind(request->reply->vps, 265, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Server-IP-Address */
+ if (!vp) vp = pairfind(request->reply->vps, 54, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-DHCP-Server-Identifier */
+ if (vp) {
+ request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ }
+ }
+
request->reply->dst_port = request->packet->src_port;
request->reply->src_port = request->packet->dst_port;
* public IP, but the gateway a private one.
*/
vp = pairfind(request->reply->vps, 272, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Relay-IP-Address */
- if (vp) {
+ if (vp && (vp->vp_ipaddr != ntohl(INADDR_ANY))) {
RDEBUG("DHCP: Reply will be unicast to giaddr from original packet");
request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
return 1;
* Answer to client's nearest DHCP gateway. In this
* case, the client can reach the gateway, as can the
* server.
+ *
+ * We also use *our* source port as the destination port.
+ * Gateways are servers, and listen on the server port,
+ * not the client port.
*/
vp = pairfind(request->reply->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
if (vp && (vp->vp_ipaddr != htonl(INADDR_ANY))) {
RDEBUG("DHCP: Reply will be unicast to giaddr");
request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ request->reply->dst_port = request->packet->dst_port;
return 1;
}
vp = pairfind(request->reply->vps, 264, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Your-IP-Address */
if (!vp) {
- DEBUG("DHCP: Failed to find DHCP-Your-IP-Address for request.");
+ RDEBUG("DHCP: Failed to find DHCP-Client-IP-Address or DHCP-Your-IP-Address for request; "
+ "not responding");
+ /*
+ * There is nowhere to send the response to, so don't bother.
+ */
+ request->reply->code = 0;
return -1;
}
}
}
#else
- RDEBUG("DHCP: Reply will be broadcast as this system does not support ARP updates");
- request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
+ if (request->packet->src_ipaddr.ipaddr.ip4addr.s_addr != ntohl(INADDR_NONE)) {
+ RDEBUG("DHCP: Request will be unicast to the unicast source IP address");
+ request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = request->packet->src_ipaddr.ipaddr.ip4addr.s_addr;
+ } else {
+ RDEBUG("DHCP: Reply will be broadcast as this system does not support ARP updates");
+ request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
+ }
#endif
return 1;
sock = this->data;
if (!sock->lsock.interface) {
- WDEBUG("No \"interface\" setting is defined. Only unicast DHCP will work.");
+ WARN("No \"interface\" setting is defined. Only unicast DHCP will work");
}
/*
if (broadcast) {
if (setsockopt(this->fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
ERROR("Can't set broadcast option: %s\n",
- strerror(errno));
+ fr_syserror(errno));
return -1;
}
}
if (setsockopt(this->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
ERROR("Can't set re-use addres option: %s\n",
- strerror(errno));
+ fr_syserror(errno));
return -1;
}
sock->suppress_responses = false;
cp = cf_pair_find(cs, "suppress_responses");
if (cp) {
- cf_item_parse(cs, "suppress_responses", PW_TYPE_BOOLEAN,
- &sock->suppress_responses, NULL);
+ cf_item_parse(cs, "suppress_responses", FR_ITEM_POINTER(PW_TYPE_BOOLEAN, &sock->suppress_responses), NULL);
}
cp = cf_pair_find(cs, "src_interface");
if (cp) {
- cf_item_parse(cs, "src_interface", PW_TYPE_STRING_PTR,
- &sock->src_interface, NULL);
+ cf_item_parse(cs, "src_interface", FR_ITEM_POINTER(PW_TYPE_STRING, &sock->src_interface), NULL);
} else {
sock->src_interface = sock->lsock.interface;
}
if (!sock->src_interface && sock->lsock.interface) {
- sock->src_interface = talloc_strdup(sock, sock->lsock.interface);
+ sock->src_interface = talloc_typed_strdup(sock, sock->lsock.interface);
}
cp = cf_pair_find(cs, "src_ipaddr");
if (cp) {
memset(&sock->src_ipaddr, 0, sizeof(sock->src_ipaddr));
sock->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_NONE);
- rcode = cf_item_parse(cs, "src_ipaddr", PW_TYPE_IPADDR,
- &sock->src_ipaddr.ipaddr.ip4addr, NULL);
+ rcode = cf_item_parse(cs, "src_ipaddr", FR_ITEM_POINTER(PW_TYPE_IPV4_ADDR, &sock->src_ipaddr), NULL);
if (rcode < 0) return -1;
sock->src_ipaddr.af = AF_INET;
client = &sock->dhcp_client;
memset(client, 0, sizeof(*client));
client->ipaddr.af = AF_INET;
- client->ipaddr.ipaddr.ip4addr.s_addr = INADDR_NONE;
- client->prefix = 0;
+ client->ipaddr.ipaddr.ip4addr.s_addr = ntohl(INADDR_NONE);
+ client->ipaddr.prefix = 0;
client->longname = client->shortname = "dhcp";
client->secret = client->shortname;
- client->nas_type = talloc_strdup(sock, "none");
+ client->nas_type = talloc_typed_strdup(sock, "none");
return 0;
}
* Allow single attribute values to be retrieved from the dhcp.
*/
static ssize_t dhcp_options_xlat(UNUSED void *instance, REQUEST *request,
- char const *fmt, char *out, size_t freespace)
+ char const *fmt, char *out, size_t freespace)
{
vp_cursor_t cursor;
VALUE_PAIR *vp, *head = NULL;
while (isspace((int) *fmt)) fmt++;
-
if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
*out = '\0';
return 0;
if ((fr_dhcp_decode_options(request->packet,
vp->vp_octets, vp->length, &head) < 0) || (!head)) {
- RWDEBUG("DHCP option decoding failed");
+ RWDEBUG("DHCP option decoding failed: %s", fr_strerror());
*out = '\0';
return -1;
}
- for (vp = paircursor(&cursor, &head);
+ for (vp = fr_cursor_init(&cursor, &head);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
decoded++;
}
return strlen(out);
}
+static ssize_t dhcp_xlat(UNUSED void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
+{
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+ uint8_t binbuf[255];
+ ssize_t len;
+
+ while (isspace((int) *fmt)) fmt++;
+
+ if ((radius_copy_vp(&vp, request, fmt) < 0) || !vp) {
+ *out = '\0';
+ return 0;
+ }
+ fr_cursor_init(&cursor, &vp);
+
+ len = fr_dhcp_encode_option(binbuf, sizeof(binbuf), request, &cursor);
+ talloc_free(vp);
+ if (len <= 0) {
+ REDEBUG("DHCP option encoding failed: %s", fr_strerror());
+
+ return -1;
+ }
+
+ if ((size_t)((len * 2) + 1) > freespace) {
+ REDEBUG("DHCP option encoding failed: Output buffer exhausted, needed %zd bytes, have %zd bytes",
+ (len * 2) + 1, freespace);
+
+ return -1;
+ }
+
+ return fr_bin2hex(out, binbuf, len);
+}
/*
* Only free memory we allocated. The strings allocated via
static int mod_detach(void *instance)
{
xlat_unregister("dhcp_options", dhcp_options_xlat, instance);
+ xlat_unregister("dhcp", dhcp_xlat, instance);
return 0;
}
rlm_dhcp_t *inst = instance;
xlat_register("dhcp_options", dhcp_options_xlat, NULL, inst);
+ xlat_register("dhcp", dhcp_xlat, NULL, inst);
return 0;
}
process_post_auth(0, request);
DEBUG2("Done VMPS");
- request->reply->code = PW_AUTHENTICATION_ACK;
+ request->reply->code = PW_CODE_AUTHENTICATION_ACK;
return 0;
}
/* @todo: this is a hack */
# define DEBUG if (fr_debug_flag && fr_log_fp) fr_printf_log
-void fr_strerror_printf(char const *fmt, ...);
# define debug_pair(vp) do { if (fr_debug_flag && fr_log_fp) { \
vp_print(fr_log_fp, vp); \
} \
UNUSED fr_ipaddr_t *src_ipaddr,
#endif
fr_ipaddr_t *dst_ipaddr,
- int dst_port)
+ uint16_t dst_port)
{
struct sockaddr_storage dst;
socklen_t sizeof_dst;
ssize_t data_len;
uint8_t header[4];
size_t len;
- int port;
+ uint16_t port;
memset(&src, 0, sizeof_src);
memset(&dst, 0, sizeof_dst);
* Check for socket errors.
*/
if (length < 0) {
- fr_strerror_printf("Error receiving packet: %s", strerror(errno));
+ fr_strerror_printf("Error receiving packet: %s", fr_syserror(errno));
/* packet->data is NULL */
rad_free(&packet);
return NULL;
/*
* This is more than a bit of a hack.
*/
- packet->code = PW_AUTHENTICATION_REQUEST;
+ packet->code = PW_CODE_AUTHENTICATION_REQUEST;
memcpy(&id, packet->data + 4, 4);
packet->id = ntohl(id);
if (packet->data_len < VQP_HDR_LEN) return -1;
- paircursor(&cursor, &packet->vps);
+ fr_cursor_init(&cursor, &packet->vps);
vp = paircreate(packet, PW_VQP_PACKET_TYPE, 0);
if (!vp) {
fr_strerror_printf("No memory");
}
vp->vp_integer = packet->data[1];
debug_pair(vp);
- pairinsert(&cursor, vp);
+ fr_cursor_insert(&cursor, vp);
vp = paircreate(packet, PW_VQP_ERROR_CODE, 0);
if (!vp) {
}
vp->vp_integer = packet->data[2];
debug_pair(vp);
- pairinsert(&cursor, vp);
+ fr_cursor_insert(&cursor, vp);
vp = paircreate(packet, PW_VQP_SEQUENCE_NUMBER, 0);
if (!vp) {
}
vp->vp_integer = packet->id; /* already set by vqp_recv */
debug_pair(vp);
- pairinsert(&cursor, vp);
+ fr_cursor_insert(&cursor, vp);
ptr = packet->data + VQP_HDR_LEN;
end = packet->data + packet->data_len;
}
switch (vp->da->type) {
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
if (length == 4) {
memcpy(&vp->vp_ipaddr, ptr, 4);
vp->length = 4;
default:
case PW_TYPE_OCTETS:
- pairmemcpy(vp, ptr, length);
+ if (length < 1024) {
+ pairmemcpy(vp, ptr, length);
+ } else {
+ pairmemcpy(vp, ptr, 1024);
+ }
break;
case PW_TYPE_STRING:
- vp->length = length;
- vp->vp_strvalue = p = talloc_array(vp, char, vp->length + 1);
- vp->type = VT_DATA;
- memcpy(p, ptr, vp->length);
- p[vp->length] = '\0';
+ if (length < 1024) {
+ vp->length = length;
+ vp->vp_strvalue = p = talloc_array(vp, char, vp->length + 1);
+ vp->type = VT_DATA;
+ memcpy(p, ptr, vp->length);
+ p[vp->length] = '\0';
+ } else {
+ vp->length = 1024;
+ vp->vp_strvalue = p = talloc_array(vp, char, 1025);
+ vp->type = VT_DATA;
+ memcpy(p, ptr, vp->length);
+ p[vp->length] = '\0';
+ }
break;
}
ptr += length;
debug_pair(vp);
- pairinsert(&cursor, vp);
+ fr_cursor_insert(&cursor, vp);
}
/*
/* Data */
switch (vp->da->type) {
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
memcpy(ptr, &vp->vp_ipaddr, 4);
break;
* going to return.
*/
typedef struct rlm_always_t {
- char *rcode_str;
+ char const *rcode_str;
rlm_rcode_t rcode;
- int simulcount;
+ uint32_t simulcount;
bool mpp;
} rlm_always_t;
* A mapping of configuration file names to internal variables.
*/
static const CONF_PARSER module_config[] = {
- { "rcode", PW_TYPE_STRING_PTR, offsetof(rlm_always_t,rcode_str),
- NULL, "fail" },
- { "simulcount", PW_TYPE_INTEGER, offsetof(rlm_always_t,simulcount),
- NULL, "0" },
- { "mpp", PW_TYPE_BOOLEAN, offsetof(rlm_always_t,mpp),
- NULL, "no" },
+ { "rcode", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_always_t, rcode_str), "fail" },
+ { "simulcount", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_always_t, simulcount), "0" },
+ { "mpp", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_always_t, mpp), "no" },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
* Just return the rcode ... this function is autz, auth, acct, and
* preacct!
*/
-static rlm_rcode_t always_return(void *instance, UNUSED REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_always_return(void *instance, UNUSED REQUEST *request)
{
return ((struct rlm_always_t *)instance)->rcode;
}
/*
* checksimul fakes some other variables besides the rcode...
*/
-static rlm_rcode_t mod_checksimul(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_checksimul(void *instance, REQUEST *request)
{
struct rlm_always_t *inst = instance;
module_t rlm_always = {
RLM_MODULE_INIT,
"always",
- RLM_TYPE_CHECK_CONFIG_SAFE, /* type */
+ 0, /* type */
sizeof(rlm_always_t), /* config size */
module_config, /* configuration */
mod_instantiate, /* instantiation */
NULL, /* detach */
{
- always_return, /* authentication */
- always_return, /* authorization */
- always_return, /* preaccounting */
- always_return, /* accounting */
+ mod_always_return, /* authentication */
+ mod_always_return, /* authorization */
+ mod_always_return, /* preaccounting */
+ mod_always_return, /* accounting */
#ifdef WITH_SESSION_MGMT
mod_checksimul, /* checksimul */
#else
NULL,
#endif
- always_return, /* pre-proxy */
- always_return, /* post-proxy */
- always_return /* post-auth */
+ mod_always_return, /* pre-proxy */
+ mod_always_return, /* post-proxy */
+ mod_always_return /* post-auth */
#ifdef WITH_COA
,
- always_return, /* recv-coa */
- always_return /* send-coa */
+ mod_always_return, /* recv-coa */
+ mod_always_return /* send-coa */
#endif
},
};
#include <ctype.h>
#include <fcntl.h>
-#include <limits.h>
-
/*
* Define a structure with the module configuration, so it can
* be used as the instance handle.
*/
typedef struct rlm_attr_filter {
- char *filename;
- char *key;
+ char const *filename;
+ char const *key;
bool relaxed;
PAIR_LIST *attrs;
} rlm_attr_filter_t;
static const CONF_PARSER module_config[] = {
- { "attrsfile", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED,
- offsetof(rlm_attr_filter_t, filename), NULL, NULL},
- { "filename", PW_TYPE_FILE_INPUT | PW_TYPE_REQUIRED,
- offsetof(rlm_attr_filter_t, filename), NULL, NULL},
- { "key", PW_TYPE_STRING_PTR,
- offsetof(rlm_attr_filter_t, key), NULL, "%{Realm}" },
- { "relaxed", PW_TYPE_BOOLEAN,
- offsetof(rlm_attr_filter_t, relaxed), NULL, "no" },
+ { "attrsfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, rlm_attr_filter_t, filename), NULL },
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_REQUIRED, rlm_attr_filter_t, filename), NULL },
+ { "key", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_attr_filter_t, key), "%{Realm}" },
+ { "relaxed", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_attr_filter_t, relaxed), "no" },
{ NULL, -1, 0, NULL, NULL }
};
-static void check_pair(VALUE_PAIR *check_item, VALUE_PAIR *reply_item,
- int *pass, int *fail)
+static void check_pair(REQUEST *request, VALUE_PAIR *check_item, VALUE_PAIR *reply_item, int *pass, int *fail)
{
int compare;
if (check_item->op == T_OP_SET) return;
compare = paircmp(check_item, reply_item);
+ if (compare < 0) {
+ REDEBUG("Comparison failed: %s", fr_strerror());
+ }
+
if (compare == 1) {
++*(pass);
} else {
++*(fail);
}
+ if (RDEBUG_ENABLED3) {
+ char rule[1024], pair[1024];
+
+ vp_prints(rule, sizeof(rule), check_item);
+ vp_prints(pair, sizeof(pair), reply_item);
+ RDEBUG3("%s %s %s", pair, compare == 1 ? "allowed by" : "disallowed by", rule);
+ }
+
return;
}
-
static int attr_filter_getfile(TALLOC_CTX *ctx, char const *filename, PAIR_LIST **pair_list)
{
vp_cursor_t cursor;
entry->check = entry->reply;
entry->reply = NULL;
- for (vp = paircursor(&cursor, &entry->check);
+ for (vp = fr_cursor_init(&cursor, &entry->check);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
/*
* If it's NOT a vendor attribute,
* and it's NOT a wire protocol
* then bitch about it, giving a good warning message.
*/
if ((vp->da->vendor == 0) &&
- (vp->da->attr > 0xff) &&
(vp->da->attr > 1000)) {
- WDEBUG("[%s]:%d Check item \"%s\"\n\tfound in filter list for realm \"%s\".\n",
+ WARN("[%s]:%d Check item \"%s\"\n\tfound in filter list for realm \"%s\".\n",
filename, entry->lineno, vp->da->name, entry->name);
}
}
/*
* Common attr_filter checks
*/
-static rlm_rcode_t attr_filter_common(void *instance, REQUEST *request, RADIUS_PACKET *packet)
+static rlm_rcode_t CC_HINT(nonnull(1,2)) attr_filter_common(void *instance, REQUEST *request, RADIUS_PACKET *packet)
{
rlm_attr_filter_t *inst = instance;
VALUE_PAIR *vp;
if (!packet) return RLM_MODULE_NOOP;
- rad_assert(request != NULL);
-
if (!inst->key) {
VALUE_PAIR *namepair;
* Head of the output list
*/
output = NULL;
- paircursor(&out, &output);
+ fr_cursor_init(&out, &output);
/*
* Find the attr_filter profile entry for the entry.
RDEBUG2("Matched entry %s at line %d", pl->name, pl->lineno);
found = 1;
- for (check_item = paircursor(&check, &pl->check);
+ for (check_item = fr_cursor_init(&check, &pl->check);
check_item;
- check_item = pairnext(&check)) {
+ check_item = fr_cursor_next(&check)) {
if (!check_item->da->vendor &&
(check_item->da->attr == PW_FALL_THROUGH) &&
(check_item->vp_integer == 1)) {
fall_through = 1;
continue;
}
- else if (!check_item->da->vendor &&
- check_item->da->attr == PW_RELAX_FILTER) {
+ else if (!check_item->da->vendor && check_item->da->attr == PW_RELAX_FILTER) {
relax_filter = check_item->vp_integer;
continue;
}
goto error;
}
radius_xlat_do(request, vp);
- pairinsert(&out, vp);
+ fr_cursor_insert(&out, vp);
}
}
* only if it matches all rules that describe an
* Idle-Timeout.
*/
- for (input_item = paircursor(&input, &packet->vps);
+ for (input_item = fr_cursor_init(&input, &packet->vps);
input_item;
- input_item = pairnext(&input)) {
- /* reset the pass,fail vars for each reply item */
- pass = fail = 0;
+ input_item = fr_cursor_next(&input)) {
+ pass = fail = 0; /* reset the pass,fail vars for each reply item */
/*
- * reset the check_item pointer to
- * beginning of the list
+ * Reset the check_item pointer to beginning of the list
*/
- for (check_item = pairfirst(&check);
+ for (check_item = fr_cursor_first(&check);
check_item;
- check_item = pairnext(&check)) {
+ check_item = fr_cursor_next(&check)) {
/*
- * Vendor-Specific is special, and
- * matches any VSA if the comparison
- * is always true.
+ * Vendor-Specific is special, and matches any VSA if the
+ * comparison is always true.
*/
if ((check_item->da->attr == PW_VENDOR_SPECIFIC) && (input_item->da->vendor != 0) &&
(check_item->op == T_OP_CMP_TRUE)) {
continue;
}
- if (input_item->da->attr == check_item->da->attr) {
- check_pair(check_item, input_item, &pass, &fail);
+ if (input_item->da == check_item->da) {
+ check_pair(request, check_item, input_item, &pass, &fail);
}
}
+ RDEBUG3("Attribute \"%s\" allowed by %i rules, disallowed by %i rules",
+ input_item->da->name, pass, fail);
/*
- * Only move attribute if it passed all rules,
- * or if the config says we should copy unmatched
- * attributes ('relaxed' mode).
+ * Only move attribute if it passed all rules, or if the config says we
+ * should copy unmatched attributes ('relaxed' mode).
*/
if (fail == 0 && (pass > 0 || relax_filter)) {
if (!pass) {
- RDEBUG3("Attribute (%s) allowed by relaxed mode", input_item->da->name);
+ RDEBUG3("Attribute \"%s\" allowed by relaxed mode", input_item->da->name);
}
vp = paircopyvp(packet, input_item);
if (!vp) {
goto error;
}
- pairinsert(&out, vp);
+ fr_cursor_insert(&out, vp);
}
}
pairfree(&packet->vps);
packet->vps = output;
- if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
+ if (request->packet->code == PW_CODE_AUTHENTICATION_REQUEST) {
request->username = pairfind(request->packet->vps, PW_STRIPPED_USER_NAME, 0, TAG_ANY);
- if (!request->username)
+ if (!request->username) {
request->username = pairfind(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ }
request->password = pairfind(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
}
return RLM_MODULE_FAIL;
}
-#define RLM_AF_FUNC(_x, _y) static rlm_rcode_t mod_##_x(void *instance, REQUEST *request) \
+#define RLM_AF_FUNC(_x, _y) static rlm_rcode_t CC_HINT(nonnull) mod_##_x(void *instance, REQUEST *request) \
{ \
return attr_filter_common(instance, request, request->_y); \
}
module_t rlm_attr_filter = {
RLM_MODULE_INIT,
"attr_filter",
- RLM_TYPE_CHECK_CONFIG_SAFE | RLM_TYPE_HUP_SAFE, /* type */
+ RLM_TYPE_HUP_SAFE, /* type */
sizeof(rlm_attr_filter_t),
module_config,
mod_instantiate, /* instantiation */
NULL, /* detach */
{
- NULL, /* authentication */
+ NULL, /* authentication */
mod_authorize, /* authorization */
mod_preacct, /* pre-acct */
mod_accounting, /* accounting */
- NULL, /* checksimul */
+ NULL, /* checksimul */
#ifdef WITH_PROXY
mod_pre_proxy, /* pre-proxy */
mod_post_proxy, /* post-proxy */
#define PW_CACHE_STATUS_ONLY 1141
#define PW_CACHE_MERGE 1142
#define PW_CACHE_ENTRY_HITS 1143
+#define PW_CACHE_READ_ONLY 1144
/*
* Define a structure for our module configuration.
*/
typedef struct rlm_cache_t {
char const *xlat_name;
- char *key;
- int ttl;
- int max_entries;
- int epoch;
+ char const *key;
+ uint32_t ttl;
+ uint32_t max_entries;
+ int32_t epoch;
bool stats;
CONF_SECTION *cs;
rbtree_t *cache;
#define MAX_ATTRMAP 128
/*
+ * A mapping of configuration file names to internal variables.
+ *
+ * Note that the string is dynamically allocated, so it MUST
+ * be freed. When the configuration file parse re-reads the string,
+ * it free's the old one, and strdup's the new one, placing the pointer
+ * to the strdup'd string into 'config.string'. This gets around
+ * buffer over-flows.
+ */
+static const CONF_PARSER module_config[] = {
+ { "key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_cache_t, key), NULL },
+ { "ttl", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_cache_t, ttl), "500" },
+ { "max_entries", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_cache_t, max_entries), "16384" },
+
+ /* Should be a type which matches time_t, @fixme before 2038 */
+ { "epoch", FR_CONF_OFFSET(PW_TYPE_SIGNED, rlm_cache_t, epoch), "0" },
+ { "add_stats", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_cache_t, stats), "no" },
+
+ { NULL, -1, 0, NULL, NULL } /* end the list */
+};
+
+
+/*
* Compare two entries by key. There may only be one entry with
* the same key.
*/
/*
* Merge a cached entry into a REQUEST.
*/
-static void cache_merge(rlm_cache_t *inst, REQUEST *request,
- rlm_cache_entry_t *c)
+static void CC_HINT(nonnull) cache_merge(rlm_cache_t *inst, REQUEST *request, rlm_cache_entry_t *c)
{
VALUE_PAIR *vp;
- rad_assert(request != NULL);
- rad_assert(c != NULL);
-
vp = pairfind(request->config_items, PW_CACHE_MERGE, 0, TAG_ANY);
if (vp && (vp->vp_integer == 0)) {
RDEBUG2("Told not to merge entry into request");
/*
* Update the expiry time based on the TTL.
* A TTL of 0 means "delete from the cache".
+ * A TTL < 0 means "delete from the cache and recreate the entry".
*/
vp = pairfind(request->config_items, PW_CACHE_TTL, 0, TAG_ANY);
if (vp) {
- if (vp->vp_integer == 0) goto delete;
+ if (vp->vp_signed <= 0) goto delete;
- ttl = vp->vp_integer;
+ ttl = vp->vp_signed;
c->expires = request->timestamp + ttl;
RDEBUG("Adding %d to the TTL", ttl);
}
}
+/** Callback for radius_map2request
+ *
+ * Simplifies merging VALUE_PAIRs into the current request.
+ */
+static int _cache_add(VALUE_PAIR **out, REQUEST *request, UNUSED value_pair_map_t const *map, void *ctx)
+{
+ VALUE_PAIR *vp;
+
+ vp = talloc_get_type_abort(ctx, VALUE_PAIR);
+ /* radius_map2request will reparent */
+ *out = paircopy(request, vp);
+
+ if (!*out) return -1;
+ return 0;
+}
+
/*
* Add an entry to the cache.
*/
-static rlm_cache_entry_t *cache_add(rlm_cache_t *inst, REQUEST *request,
- char const *key)
+static rlm_cache_entry_t *cache_add(rlm_cache_t *inst, REQUEST *request, char const *key)
{
int ttl;
- VALUE_PAIR *vp, *found, **to_req, **to_cache, **from;
- DICT_ATTR const *da;
+ VALUE_PAIR *vp, *to_cache;
+ vp_cursor_t src_list, cached_request, cached_reply, cached_control;
- int merge = true;
- REQUEST *context;
+ bool merge = true;
value_pair_map_t const *map;
rlm_cache_entry_t *c;
- char buffer[1024];
if (rbtree_num_elements(inst->cache) >= inst->max_entries) {
RDEBUG("Cache is full: %d entries", inst->max_entries);
* TTL of 0 means "don't cache this entry"
*/
vp = pairfind(request->config_items, PW_CACHE_TTL, 0, TAG_ANY);
- if (vp && (vp->vp_integer == 0)) return NULL;
+ if (vp && (vp->vp_signed == 0)) return NULL;
c = talloc_zero(inst, rlm_cache_entry_t);
- c->key = talloc_strdup(c, key);
+ c->key = talloc_typed_strdup(c, key);
c->created = c->expires = request->timestamp;
/*
- * Use per-entry TTL, or globally defined one.
+ * Use per-entry TTL if > 0, or globally defined one.
*/
- if (vp) {
- ttl = vp->vp_integer;
- } else {
- ttl = inst->ttl;
- }
+ ttl = vp && (vp->vp_signed > 0) ? vp->vp_integer : inst->ttl;
c->expires += ttl;
RDEBUG("Creating entry for \"%s\"", key);
RDEBUG2("Told not to merge new entry into request");
}
- for (map = inst->maps; map != NULL; map = map->next) {
- rad_assert(map->dst && map->src);
+ fr_cursor_init(&cached_request, &c->packet);
+ fr_cursor_init(&cached_reply, &c->reply);
+ fr_cursor_init(&cached_control, &c->control);
- /*
- * Specifying inner/outer request doesn't work here
- * but there's no easy fix...
- */
- switch (map->dst->list) {
- case PAIR_LIST_REQUEST:
- to_cache = &c->packet;
- break;
-
- case PAIR_LIST_REPLY:
- to_cache = &c->reply;
- break;
+ for (map = inst->maps; map != NULL; map = map->next) {
+ bool do_merge = merge;
- case PAIR_LIST_CONTROL:
- to_cache = &c->control;
- break;
+ rad_assert(map->dst && map->src);
- default:
- rad_assert(0);
- return NULL;
+ if (radius_map2vp(&to_cache, request, map, NULL) < 0) {
+ RDEBUG("Skipping %s", map->src->name);
+ continue;
}
/*
- * Resolve the destination in the current request.
- * We need to add the to_cache there too if any of these
- * are.
- * true :
+ * Merge attributes into the current request if:
* - Map specifies an xlat'd string.
* - Map specifies a literal string.
+ * - Map specifies an exec.
* - Map src and dst lists differ.
* - Map src and dst attributes differ
+ *
+ * Unless Cache-Merge = no
*/
- to_req = NULL;
- if (merge && ( !map->src->da ||
- (map->src->list != map->dst->list) ||
- (map->src->da != map->dst->da))) {
- context = request;
- /*
- * It's ok if the list isn't valid here...
- * It might be valid later when we merge
- * the cache entry.
- */
- if (radius_request(&context, map->dst->request) == 0) {
- to_req = radius_list(context, map->dst->list);
- }
- }
-
- /*
- * We infer that src was an attribute ref from the fact
- * it contains a da.
- */
- RDEBUG4(":: dst is \"%s\" src is \"%s\"",
- fr_int2str(vpt_types, map->dst->type, "<INVALID>"),
- fr_int2str(vpt_types, map->src->type, "<INVALID>"));
-
- switch (map->src->type) {
- case VPT_TYPE_ATTR:
- {
- vp_cursor_t cursor;
-
- from = NULL;
- da = map->src->da;
- context = request;
- if (radius_request(&context, map->src->request) == 0) {
- from = radius_list(context, map->src->list);
- }
-
- /*
- * Can't add the attribute if the list isn't
- * valid.
- */
- if (!from) continue;
-
- paircursor(&cursor, from);
- found = pairfindnext(&cursor, da->attr, da->vendor, TAG_ANY);
- if (!found) {
- RWDEBUG("\"%s\" not found, skipping",
- map->src->name);
- continue;
- }
+ if (do_merge) switch (map->src->type) {
+ case VPT_TYPE_LITERAL:
+ case VPT_TYPE_XLAT:
+ case VPT_TYPE_EXEC:
+ break;
- RDEBUG("\t%s %s %s", map->dst->name,
- fr_int2str(fr_tokens, map->op, "<INVALID>"),
- map->src->name);
-
- switch (map->op) {
- case T_OP_SET:
- case T_OP_EQ:
- case T_OP_SUB:
- vp = map->dst->type == VPT_TYPE_LIST ?
- paircopyvp(c, found) :
- paircopyvpdata(c, map->dst->da, found);
-
- if (!vp) continue;
-
- pairadd(to_cache, vp);
-
- if (to_req) {
- vp = paircopyvp(request, vp);
- radius_pairmove(request, to_req, vp);
- }
-
- break;
- case T_OP_ADD:
- do {
- vp = map->dst->type == VPT_TYPE_LIST ?
- paircopyvp(c, found) :
- paircopyvpdata(c, map->dst->da, found);
- if (!vp) continue;
-
- vp->op = map->op;
- pairadd(to_cache, vp);
-
- if (to_req) {
- vp = paircopyvp(request, vp);
- radius_pairmove(request, to_req, vp);
-
- }
- } while ((found = pairfindnext(&cursor, da->attr, da->vendor, TAG_ANY)));
- break;
-
- default:
- rad_assert(0);
- return NULL;
- }
- break;
- }
case VPT_TYPE_LIST:
- {
- vp_cursor_t in, out;
- VALUE_PAIR *i;
-
- rad_assert(map->src->type == VPT_TYPE_LIST);
+ if (map->src->vpt_list == map->dst->vpt_list) do_merge = false;
+ break;
- from = NULL;
- context = request;
- if (radius_request(&context, map->src->request) == 0) {
- from = radius_list(context, map->src->list);
- }
- if (!from) continue;
-
- found = NULL;
- paircursor(&out, &found);
- for (i = paircursor(&in, from);
- i != NULL;
- i = pairnext(&in)) {
- /*
- * Prevent cache control attributes being added to the cache.
- */
- switch (i->da->attr) {
- case PW_CACHE_TTL:
- case PW_CACHE_STATUS_ONLY:
- case PW_CACHE_MERGE:
- case PW_CACHE_ENTRY_HITS:
- RDEBUG("\tskipping %s", i->da->name);
- continue;
- default:
- break;
- }
-
- vp = paircopyvp(c, i);
- if (!vp) {
- pairfree(&found);
- return NULL;
- }
- RDEBUG("\t%s %s %s (%s)", map->dst->name,
- fr_int2str(fr_tokens, map->op, "<INVALID>"),
- map->src->name, vp->da->name);
- vp->op = map->op;
- pairinsert(&out, vp);
- }
+ case VPT_TYPE_ATTR:
+ if (map->src->vpt_da == map->dst->vpt_da) do_merge = false;
+ break;
- pairadd(to_cache, found);
- if (to_req) {
- vp = paircopy(request, found);
- radius_pairmove(request, to_req, vp);
- }
+ default:
+ do_merge = false;
+ }
- break;
- }
/*
- * It was most likely a double quoted string that now
- * needs to be expanded.
+ * Reparent the VPs radius_map2vp may return multiple.
*/
- case VPT_TYPE_XLAT:
- if (radius_xlat(buffer, sizeof(buffer), request, map->src->name, NULL, NULL) <= 0) {
+ for (vp = fr_cursor_init(&src_list, &to_cache);
+ vp;
+ vp = fr_cursor_next(&src_list)) {
+ VERIFY_VP(vp);
+
+ /*
+ * Prevent people from accidentally caching
+ * cache control attributes.
+ */
+ if (map->src->type == VPT_TYPE_LIST) switch (vp->da->attr) {
+ case PW_CACHE_TTL:
+ case PW_CACHE_STATUS_ONLY:
+ case PW_CACHE_READ_ONLY:
+ case PW_CACHE_MERGE:
+ case PW_CACHE_ENTRY_HITS:
+ RDEBUG2("Skipping %s", vp->da->name);
continue;
+ default:
+ break;
}
- RDEBUG("\t%s %s \"%s\"", map->dst->name,
- fr_int2str(fr_tokens, map->op, "<INVALID>"),
- buffer);
-
- vp = pairalloc(NULL, map->dst->da);
- if (!vp) continue;
+ RDEBUG2("Adding to cache entry:");
+ if (debug_flag) radius_map_debug(request, map, vp);
+ (void) talloc_steal(c, vp);
vp->op = map->op;
- if (!pairparsevalue(vp, buffer)) {
- pairfree(&vp);
- continue;
- }
- pairadd(to_cache, vp);
-
- if (to_req) {
- vp = paircopyvp(request, vp);
- radius_pairmove(request, to_req, vp);
- }
+ switch (map->dst->vpt_list) {
+ case PAIR_LIST_REQUEST:
+ fr_cursor_insert(&cached_request, vp);
+ break;
- break;
- /*
- * Literal string.
- */
- case VPT_TYPE_LITERAL:
- RDEBUG("\t%s %s '%s'", map->dst->name,
- fr_int2str(fr_tokens, map->op, "<INVALID>"),
- map->src->name);
+ case PAIR_LIST_REPLY:
+ fr_cursor_insert(&cached_reply, vp);
+ break;
- vp = pairalloc(NULL, map->dst->da);
- if (!vp) continue;
+ case PAIR_LIST_CONTROL:
+ fr_cursor_insert(&cached_control, vp);
+ break;
- vp->op = map->op;
- if (!pairparsevalue(vp, map->src->name)) {
- pairfree(&vp);
- continue;
+ default:
+ rad_assert(0); /* should have been caught by validation */
}
- pairadd(to_cache, vp);
-
- if (to_req) {
- vp = paircopyvp(request, vp);
- radius_pairmove(request, to_req, vp);
+ if (do_merge && radius_map_dst_valid(request, map)) {
+ /* There's no reason for this to fail (we checked the dst was valid) */
+ RDEBUG2("Adding to request:");
+ if (radius_map2request(request, map, _cache_add, vp) < 0) rad_assert(0);
}
-
- break;
-
- default:
- rad_assert(0);
- return NULL;
}
}
return -1;
}
+ /*
+ * Can't copy an xlat expansion or literal into a list,
+ * we don't know what type of attribute we'd need
+ * to create.
+ *
+ * The only exception is where were using a unary
+ * operator like !*.
+ */
+ if ((map->dst->type == VPT_TYPE_LIST) &&
+ (map->op != T_OP_CMP_FALSE) &&
+ ((map->src->type == VPT_TYPE_XLAT) || (map->src->type == VPT_TYPE_LITERAL))) {
+ cf_log_err(map->ci, "Can't copy value into list (we don't know which attribute to create)");
+
+ return -1;
+ }
+
switch (map->src->type) {
case VPT_TYPE_EXEC:
cf_log_err(map->ci, "Exec values are not allowed");
*/
if (map->dst->type == VPT_TYPE_ATTR) {
VALUE_PAIR *vp;
- bool ret;
+ int ret;
- MEM(vp = pairalloc(NULL, map->dst->da));
+ MEM(vp = pairalloc(map->dst, map->dst->vpt_da));
vp->op = map->op;
- ret = pairparsevalue(vp, map->src->name);
+ ret = pairparsevalue(vp, map->src->name, 0);
talloc_free(vp);
- if (!ret) {
+ if (ret < 0) {
cf_log_err(map->ci, "%s", fr_strerror());
return -1;
}
static ssize_t cache_xlat(void *instance, REQUEST *request,
char const *fmt, char *out, size_t freespace)
{
- rlm_cache_entry_t *c;
- rlm_cache_t *inst = instance;
- VALUE_PAIR *vp, *vps;
- pair_lists_t list;
- DICT_ATTR const *target;
- char const *p = fmt;
- int ret = 0;
+ rlm_cache_entry_t *c;
+ rlm_cache_t *inst = instance;
+ VALUE_PAIR *vp, *vps;
+ pair_lists_t list;
+ DICT_ATTR const *target;
+ char const *p = fmt;
+ size_t len;
+ int ret = 0;
list = radius_list_name(&p, PAIR_LIST_REQUEST);
default:
PTHREAD_MUTEX_UNLOCK(&inst->cache_mutex);
REDEBUG("Unsupported list \"%s\"",
- fr_int2str(pair_lists, list, "¿Unknown?"));
+ fr_int2str(pair_lists, list, "<UNKNOWN>"));
return -1;
}
goto done;
}
- ret = vp_prints_value(out, freespace, vp, 0);
+ len = vp_prints_value(out, freespace, vp, 0);
+ if (is_truncated(len, freespace)) {
+ PTHREAD_MUTEX_UNLOCK(&inst->cache_mutex);
+ REDEBUG("Insufficient buffer space to write cached value");
+ return -1;
+ }
done:
PTHREAD_MUTEX_UNLOCK(&inst->cache_mutex);
}
/*
- * A mapping of configuration file names to internal variables.
- *
- * Note that the string is dynamically allocated, so it MUST
- * be freed. When the configuration file parse re-reads the string,
- * it free's the old one, and strdup's the new one, placing the pointer
- * to the strdup'd string into 'config.string'. This gets around
- * buffer over-flows.
- */
-static const CONF_PARSER module_config[] = {
- { "key", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
- offsetof(rlm_cache_t, key), NULL, NULL},
- { "ttl", PW_TYPE_INTEGER,
- offsetof(rlm_cache_t, ttl), NULL, "500" },
- { "max_entries", PW_TYPE_INTEGER,
- offsetof(rlm_cache_t, max_entries), NULL, "16384" },
- { "epoch", PW_TYPE_INTEGER,
- offsetof(rlm_cache_t, epoch), NULL, "0" },
- { "add_stats", PW_TYPE_BOOLEAN,
- offsetof(rlm_cache_t, stats), NULL, "no" },
-
- { NULL, -1, 0, NULL, NULL } /* end the list */
-};
-
-
-/*
* Only free memory we allocated. The strings allocated via
* cf_section_parse() do not need to be freed.
*/
#ifdef HAVE_PTHREAD_H
if (pthread_mutex_init(&inst->cache_mutex, NULL) < 0) {
- EDEBUG("Failed initializing mutex: %s",
- strerror(errno));
+ ERROR("Failed initializing mutex: %s",
+ fr_syserror(errno));
return -1;
}
#endif
*/
inst->cache = rbtree_create(cache_entry_cmp, cache_entry_free, 0);
if (!inst->cache) {
- EDEBUG("Failed to create cache");
+ ERROR("Failed to create cache");
return -1;
}
inst->heap = fr_heap_create(cache_heap_cmp,
offsetof(rlm_cache_entry_t, offset));
if (!inst->heap) {
- EDEBUG("Failed to create heap for the cache");
+ ERROR("Failed to create heap for the cache");
return -1;
}
* If you want to cache something different in different sections,
* configure another cache module.
*/
-static rlm_rcode_t cache_it(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_cache_it(void *instance, REQUEST *request)
{
rlm_cache_entry_t *c;
rlm_cache_t *inst = instance;
+ vp_cursor_t cursor;
VALUE_PAIR *vp;
char buffer[1024];
rlm_rcode_t rcode;
goto done;
}
+ vp = pairfind(request->config_items, PW_CACHE_READ_ONLY, 0, TAG_ANY);
+ if (vp && vp->vp_integer) {
+ rcode = RLM_MODULE_NOTFOUND;
+ goto done;
+ }
+
c = cache_add(inst, request, buffer);
if (!c) {
rcode = RLM_MODULE_NOOP;
done:
PTHREAD_MUTEX_UNLOCK(&inst->cache_mutex);
+
+ /*
+ * Reset control attributes
+ */
+ for (vp = fr_cursor_init(&cursor, &request->config_items);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ if (vp->da->vendor == 0) switch (vp->da->attr) {
+ case PW_CACHE_TTL:
+ case PW_CACHE_READ_ONLY:
+ case PW_CACHE_MERGE:
+ fr_cursor_remove(&cursor);
+ break;
+ }
+ }
+
return rcode;
}
mod_detach, /* detach */
{
NULL, /* authentication */
- cache_it, /* authorization */
- cache_it, /* preaccounting */
- cache_it, /* accounting */
+ mod_cache_it, /* authorization */
+ mod_cache_it, /* preaccounting */
+ mod_cache_it, /* accounting */
NULL, /* checksimul */
- cache_it, /* pre-proxy */
- cache_it, /* post-proxy */
- cache_it, /* post-auth */
+ mod_cache_it, /* pre-proxy */
+ mod_cache_it, /* post-proxy */
+ mod_cache_it, /* post-auth */
},
};
#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/modules.h>
-static rlm_rcode_t mod_authorize(UNUSED void *instance,
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance,
UNUSED REQUEST *request)
{
if (!pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) {
* from the database. The authentication code only needs to check
* the password, the rest is done here.
*/
-static rlm_rcode_t mod_authenticate(UNUSED void *instance,
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(UNUSED void *instance,
UNUSED REQUEST *request)
{
VALUE_PAIR *passwd_item, *chap;
if (pairfind(request->config_items, PW_USER_PASSWORD, 0, TAG_ANY) != NULL){
REDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
REDEBUG("!!! Please update your configuration so that the \"known !!!");
- REDEBUG("!!! good\" clear text password is in Cleartext-Password, !!!");
+ REDEBUG("!!! good\" cleartext password is in Cleartext-Password, !!!");
REDEBUG("!!! and NOT in User-Password. !!!");
REDEBUG("!!! !!!");
REDEBUG("!!! Authentication will fail because of this. !!!");
REDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
- REDEBUG("Clear-Text password is required for authentication");
+ REDEBUG("Cleartext password is required for authentication");
return RLM_MODULE_INVALID;
}
- RDEBUG("Using Clear-Text password \"%s\" for user %s authentication.",
- passwd_item->vp_strvalue, request->username->vp_strvalue);
+ rad_chap_encode(request->packet, pass_str,
+ chap->vp_octets[0], passwd_item);
- rad_chap_encode(request->packet,pass_str,
- chap->vp_octets[0],passwd_item);
+ if (RDEBUG_ENABLED3) {
+ uint8_t const *p;
+ size_t length;
+ VALUE_PAIR *vp;
+ char buffer[CHAP_VALUE_LENGTH * 2 + 1];
+
+ RDEBUG3("Comparing with \"known good\" Cleartext-Password \"%s\"", passwd_item->vp_strvalue);
+
+ vp = pairfind(request->packet->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY);
+ if (vp) {
+ p = vp->vp_octets;
+ length = vp->length;
+ } else {
+ p = request->packet->vector;
+ length = sizeof(request->packet->vector);
+ }
+
+ fr_bin2hex(buffer, p, length);
+ RINDENT();
+ RDEBUG3("CHAP challenge : %s", buffer);
+
+ fr_bin2hex(buffer, chap->vp_octets + 1, CHAP_VALUE_LENGTH);
+ RDEBUG3("Client sent : %s", buffer);
+
+ fr_bin2hex(buffer, pass_str + 1, CHAP_VALUE_LENGTH);
+ RDEBUG3("We calculated : %s", buffer);
+ REXDENT();
+ } else {
+ RDEBUG2("Comparing with \"known good\" Cleartext-Password");
+ }
if (rad_digest_cmp(pass_str + 1, chap->vp_octets + 1,
CHAP_VALUE_LENGTH) != 0) {
module_t rlm_chap = {
RLM_MODULE_INIT,
"CHAP",
- RLM_TYPE_CHECK_CONFIG_SAFE, /* type */
+ 0, /* type */
0,
NULL, /* CONF_PARSER */
NULL, /* instantiation */
--- /dev/null
+rlm_couchbase
+=============
+
+General
+-------
+
+This module allows you to write accounting data directly to Couchbase as JSON documents and authorize users from JSON documents stored within Couchbase. It was tested to handle thousands of radius requests per second from several thousand Aerohive access points using a FreeRADIUS installation with this module for accounting and authorization. You should list the ```couchbase``` module in both the ```accounting``` and ```authorization``` sections of your site configuration if you are planning to use it for both purposes. You should also have ```pap``` enabled for authenticating users based on cleartext or hashed password attributes. As always YMMV.
+
+Accounting
+----------
+
+You can use any radius attribute available in the accounting request to build the key for storing the accounting documents. The default configuration will try to use 'Acct-Unique-Session-Id' and fallback to 'Acct-Session-Id' if 'Acct-Unique-Session-Id' is not present. You will need to have the ```acct_unique``` policy in the ```preacct``` section of your configuration to generate the unique id attribute. Different status types (start/stop/update) are merged into a single document to facilitate querying and reporting via views. When everything is configured correctly you will see accounting requests recorded as JSON documents in your Couchbaase cluster. You have full control over what attributes are recorded and how those attributes are mapped to JSON element names via the configuration descibed later in this document.
+
+This exmaple is from an Aerohive wireless access point.
+
+```
+{
+ "docType": "radacct",
+ "startTimestamp": "Jul 15 2013 13:22:07 CDT",
+ "stopTimestamp": "null",
+ "sessionId": "51D241D3-0000047A",
+ "lastStatus": 3,
+ "authentic": 1,
+ "userName": "mruser@blargs.com",
+ "nasIpAddress": "172.28.4.150",
+ "nasIdentifier": "air4.corp.blargs.com",
+ "nasPort": 0,
+ "calledStationId": "40-18-b1-01-3c-54",
+ "framedIpAddress": "172.27.2.87",
+ "callingStationId": "8C-2D-AA-72-36-BA",
+ "nasPortType": 19,
+ "connectInfo": "11ng",
+ "sessionTime": 5821,
+ "inputPackets": 5591,
+ "inputOctets": 681742,
+ "inputGigawords": 0,
+ "outputOctets": 536306,
+ "outputGigawords": 0,
+ "outputPackets": 1087,
+ "lastUpdated": "Jul 15 2013 14:59:08 CDT",
+ "uniqueId": "029d975fc48ecb41444da52a65e62a55",
+ "calledStationSSID": "BLARGS-WIFI",
+ "strippedUserName": "mruser",
+ "strippedUserDomain": "blargs.com"
+}
+```
+
+To generate the 'calledStationSSID' fields you will need to use the ```rewrite_called_station_id``` policy in the ```preacct``` section of your config. Similarly to get the 'Stripped-User-Name' and 'Stripped-User-Domain' attributes you can create a file in ```raddb/policy.d/``` with the following content:
+
+```
+## simple nt domain regex
+simple_nt_regexp = "^([^\\\\\\\\]*)(\\\\\\\\(.*))$"
+
+## simple nai regex
+simple_nai_regexp = "^([^@]*)(@(.*))$"
+
+## split user@domain and domain\user formats
+strip_user_domain {
+ if(User-Name && (User-Name =~ /${policy.simple_nt_regexp}/)){
+ update request {
+ Stripped-User-Domain = "%{1}"
+ Stripped-User-Name = "%{3}"
+ }
+ }
+ elsif(User-Name && (User-Name =~ /${policy.simple_nai_regexp}/)){
+ update request {
+ Stripped-User-Name = "%{1}"
+ Stripped-User-Domain = "%{3}"
+ }
+ }
+ else {
+ noop
+ }
+}
+```
+
+You can then reference this policy in both the ```preacct``` and ```authorization``` sections of your configuration before calling this module.
+
+Authorization
+-------------
+
+The authorization funcionality relies on the user documents being stored with deterministic keys based on information available in the authorization request. The format of those keys may be specified in unlang like the example below:
+
+```user_key = "raduser_%{md5:%{tolower:%{%{Stripped-User-Name}:-%{User-Name}}}}"```
+
+This will create an md5 hash of the lowercase 'Stripped-User-Name' attribute or the 'User-Name' attribute if 'Stripped-User-Name' doesn't exist. The module will then attempt to fetch the resulting key from the configured couchbase bucket.
+
+The document structure is straight forward and flexible:
+
+```json
+{
+ "docType": "raduser",
+ "userName": "test",
+ "config": {
+ "SHA-Password": {
+ "value": "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3",
+ "op": ":="
+ }
+ },
+ "reply": {
+ "Reply-Message": {
+ "value": "Hidey Ho!",
+ "op": "="
+ }
+ }
+}
+```
+
+You may specify any valid combination of attributes and operations in the JSON document.
+
+To Use
+------
+
+Pull freeradius-server master and clone this module under src/modules. Then enable and compile as usual.
+You will also need the following libraries:
+
+* [libcouchbase](https://github.com/couchbase/libcouchbase) >= 2.0.0 with a valid libio module
+* [json-c](https://github.com/json-c/json-c) >= 0.9 (0.10+ HIGHLY encouraged)
+
+Configuration
+-------------
+
+```
+couchbase {
+ #
+ # List of Couchbase hosts (hosts may be space, tab, comma or semi-colon separated).
+ # Ports are optional if servers are listening on the standard port.
+ # Complete pool urls are preferred.
+ #
+ server = "http://cb01.blargs.com:8091/pools/ http://cb04.blargs.com:8091/pools/"
+
+ # Couchbase bucket name
+ bucket = "radius"
+
+ # Couchbase bucket password (optional)
+ #password = "password"
+
+ # Couchbase accounting document key (unlang supported)
+ acct_key = "radacct_%{%{Acct-Unique-Session-Id}:-%{Acct-Session-Id}}"
+
+ # Value for the 'docType' element in the json body for accounting documents
+ doctype = "radacct"
+
+ ## Accounting document expire time in seconds (0 = never)
+ expire = 2592000
+
+ #
+ # Map attribute names to json element names for accounting.
+ #
+ # Configuration items are in the format:
+ # <element name> = '<radius attribute>'
+ #
+ # Attribute names should be single quoted.
+ #
+ # Note: Atrributes not in this map will not be recorded.
+ #
+ map {
+ sessionId = 'Acct-Session-Id'
+ uniqueId = 'Acct-Unique-Session-Id'
+ lastStatus = 'Acct-Status-Type'
+ authentic = 'Acct-Authentic'
+ userName = 'User-Name'
+ strippedUserName = 'Stripped-User-Name'
+ strippedUserDomain = 'Stripped-User-Domain'
+ realm = 'Realm'
+ nasIpAddress = 'NAS-IP-Address'
+ nasIdentifier = 'NAS-Identifier'
+ nasPort = 'NAS-Port'
+ calledStationId = 'Called-Station-Id'
+ calledStationSSID = 'Called-Station-SSID'
+ callingStationId = 'Calling-Station-Id'
+ framedIpAddress = 'Framed-IP-Address'
+ nasPortType = 'NAS-Port-Type'
+ connectInfo = 'Connect-Info'
+ sessionTime = 'Acct-Session-Time'
+ inputPackets = 'Acct-Input-Packets'
+ outputPackets = 'Acct-Output-Packets'
+ inputOctets = 'Acct-Input-Octets'
+ outputOctets = 'Acct-Output-Octets'
+ inputGigawords = 'Acct-Input-Gigawords'
+ outputGigawords = 'Acct-Output-Gigawords'
+ lastUpdated = 'Event-Timestamp'
+ }
+
+ # Couchbase document key for user documents (unlang supported)
+ user_key = "raduser_%{md5:%{tolower:%{%{Stripped-User-Name}:-%{User-Name}}}}"
+
+ #
+ # The connection pool is new for 3.0, and will be used in many
+ # modules, for all kinds of connection-related activity.
+ #
+ pool {
+ # Number of connections to start
+ start = 5
+
+ # Minimum number of connections to keep open
+ min = 5
+
+ # Maximum number of connections
+ #
+ # If these connections are all in use and a new one
+ # is requested, the request will NOT get a connection.
+ #
+ # NOTE: This should be greater than or equal to "min" above.
+ max = 20
+
+ # Spare connections to be left idle
+ #
+ # NOTE: Idle connections WILL be closed if "idle_timeout"
+ # is set. This should be less than or equal to "max" above.
+ spare = 15
+
+ # Number of uses before the connection is closed
+ #
+ # NOTE: A setting of 0 means infinite (no limit).
+ uses = 0
+
+ # The lifetime (in seconds) of the connection
+ #
+ # NOTE: A setting of 0 means infinite (no limit).
+ lifetime = 0
+
+ # The idle timeout (in seconds). A connection which is
+ # unused for this length of time will be closed.
+ #
+ # NOTE: A setting of 0 means infinite (no timeout).
+ idle_timeout = 1200
+
+ # NOTE: All configuration settings are enforced. If a
+ # connection is closed because of "idle_timeout",
+ # "uses", or "lifetime", then the total number of
+ # connections MAY fall below "min". When that
+ # happens, it will open a new connection. It will
+ # also log a WARNING message.
+ #
+ # The solution is to either lower the "min" connections,
+ # or increase lifetime/idle_timeout.
+ }
+}
+```
--- /dev/null
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c mod.c jsonc_missing.c couchbase.c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
+
+# TODO: create man page
+#MAN := rlm_couchbase.8
--- /dev/null
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the `json_c_version' function. */
+#undef HAVE_JSON_C_VERSION
+
+/* Define to 1 if you have the `json_object_get_string_len' function. */
+#undef HAVE_JSON_OBJECT_GET_STRING_LEN
+
+/* Define to 1 if you have the `json_object_new_int64' function. */
+#undef HAVE_JSON_OBJECT_NEW_INT64
+
+/* Define to 1 if you have the `json_object_object_get_ex' function. */
+#undef HAVE_JSON_OBJECT_OBJECT_GET_EX
+
+/* Define to 1 if you have the `json_tokener_error_desc' function. */
+#undef HAVE_JSON_TOKENER_ERROR_DESC
+
+/* Define to 1 if you have the `json_tokener_get_error' function. */
+#undef HAVE_JSON_TOKENER_GET_ERROR
+
+/* Define to 1 if you have the `json_tokener_parse_verbose' function. */
+#undef HAVE_JSON_TOKENER_PARSE_VERBOSE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
--- /dev/null
+#! /bin/sh
+# From configure.ac Revision.
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="rlm_couchbase.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+targetname
+mod_ldflags
+mod_cflags
+CPP
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_jsonc_include_dir
+with_jsonc_lib_dir
+with_jsonc_dir
+with_libcouchbase_include_dir
+with_libcouchbase_lib_dir
+with_libcouchbase_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-jsonc-include-dir=DIR
+ Directory where the json-c includes may be found
+ --with-jsonc-lib-dir=DIR
+ Directory where the json-c libraries may be found
+ --with-jsonc-dir=DIR Base directory where json-c is installed
+ --with-libcouchbase-include-dir=DIR
+ Directory where the libcouchbase includes may be
+ found
+ --with-libcouchbase-lib-dir=DIR
+ Directory where the libcouchbase libraries may be
+ found
+ --with-libcouchbase-dir=DIR
+ Base directory where libcouchbase is installed
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+if test x$with_rlm_couchbase != xno; then
+
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+ jsonc_include_dir=
+
+# Check whether --with-jsonc-include-dir was given.
+if test "${with_jsonc_include_dir+set}" = set; then :
+ withval=$with_jsonc_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need jsonc-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ jsonc_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+ jsonc_lib_dir=
+
+# Check whether --with-jsonc-lib-dir was given.
+if test "${with_jsonc_lib_dir+set}" = set; then :
+ withval=$with_jsonc_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need jsonc-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ jsonc_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-jsonc-dir was given.
+if test "${with_jsonc_dir+set}" = set; then :
+ withval=$with_jsonc_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need json-c-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ jsonc_lib_dir="$withval/lib"
+ jsonc_include_dir="$withval/include"
+ ;;
+ esac
+fi
+
+
+
+ have_json="yes"
+ smart_try_dir="$jsonc_include_dir"
+
+
+
+ac_safe=`echo "json/json.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
+smart_include=
+smart_include_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 json/json.h in $try" >&5
+$as_echo_n "checking for json/json.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <json/json.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
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for json/json.h" >&5
+$as_echo_n "checking for json/json.h... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <json/json.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
+
+
+if test "x$LOCATE" != "x"; then
+ DIRS=
+ file=json/json.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 /usr/local/include /opt/include; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for json/json.h in $try" >&5
+$as_echo_n "checking for json/json.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <json/json.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
+
+ if test "x$ac_cv_header_json_json_h" != "xyes"; then
+ have_json="no"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: json-c headers not found. Use --with-jsonc-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: json-c headers not found. Use --with-jsonc-include-dir=<path>." >&2;}
+ fi
+
+
+ smart_try_dir="$jsonc_lib_dir"
+
+
+sm_lib_safe=`echo "json-c" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "json_c_version" | 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 json_c_version in -ljson-c in $try" >&5
+$as_echo_n "checking for json_c_version in -ljson-c in $try... " >&6; }
+ LIBS="-ljson-c $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char json_c_version();
+int
+main ()
+{
+json_c_version()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ljson-c"
+ 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 json_c_version in -ljson-c" >&5
+$as_echo_n "checking for json_c_version in -ljson-c... " >&6; }
+ LIBS="-ljson-c $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char json_c_version();
+int
+main ()
+{
+json_c_version()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ljson-c"
+ { $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=libjson-c${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=libjson-c.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 json_c_version in -ljson-c in $try" >&5
+$as_echo_n "checking for json_c_version in -ljson-c in $try... " >&6; }
+ LIBS="-ljson-c $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char json_c_version();
+int
+main ()
+{
+json_c_version()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ljson-c"
+ 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_json_c_json_c_version" != "xyes"
+ then
+
+
+sm_lib_safe=`echo "json" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "json_tokener_new" | 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 json_tokener_new in -ljson in $try" >&5
+$as_echo_n "checking for json_tokener_new in -ljson in $try... " >&6; }
+ LIBS="-ljson $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char json_tokener_new();
+int
+main ()
+{
+json_tokener_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ljson"
+ 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 json_tokener_new in -ljson" >&5
+$as_echo_n "checking for json_tokener_new in -ljson... " >&6; }
+ LIBS="-ljson $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char json_tokener_new();
+int
+main ()
+{
+json_tokener_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ljson"
+ { $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=libjson${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=libjson.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 json_tokener_new in -ljson in $try" >&5
+$as_echo_n "checking for json_tokener_new in -ljson in $try... " >&6; }
+ LIBS="-ljson $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char json_tokener_new();
+int
+main ()
+{
+json_tokener_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ljson"
+ 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_json_json_tokener_new" != "xyes"
+ then
+ have_json="no"
+ fi
+ fi
+
+ if test "x$have_json" = "xyes"; then
+ LDFLAGS="$SMART_LIBS"
+
+ for ac_func in \
+ json_c_version \
+ json_object_get_string_len \
+ json_object_object_get_ex \
+ json_object_new_int64 \
+ json_tokener_parse_verbose \
+ json_tokener_error_desc \
+ json_tokener_get_error
+
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+ else
+ fail="$fail json-c"
+ fi
+
+
+ libcouchbase_include_dir=
+
+# Check whether --with-libcouchbase-include-dir was given.
+if test "${with_libcouchbase_include_dir+set}" = set; then :
+ withval=$with_libcouchbase_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need libcouchbase-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ libcouchbase_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+ libcouchbase_lib_dir=
+
+# Check whether --with-libcouchbase-lib-dir was given.
+if test "${with_libcouchbase_lib_dir+set}" = set; then :
+ withval=$with_libcouchbase_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need libcouchbase-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ libcouchbase_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-libcouchbase-dir was given.
+if test "${with_libcouchbase_dir+set}" = set; then :
+ withval=$with_libcouchbase_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need libcouchbase-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ libcouchbase_lib_dir="$withval/lib"
+ libcouchbase_include_dir="$withval/include"
+ ;;
+ esac
+fi
+
+
+
+ have_couchbase="yes"
+ smart_try_dir="$libcouchbase_include_dir"
+
+
+ac_safe=`echo "libcouchbase/couchbase.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
+smart_include=
+smart_include_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 libcouchbase/couchbase.h in $try" >&5
+$as_echo_n "checking for libcouchbase/couchbase.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <libcouchbase/couchbase.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
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libcouchbase/couchbase.h" >&5
+$as_echo_n "checking for libcouchbase/couchbase.h... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <libcouchbase/couchbase.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
+
+
+if test "x$LOCATE" != "x"; then
+ DIRS=
+ file=libcouchbase/couchbase.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 /usr/local/include /opt/include; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libcouchbase/couchbase.h in $try" >&5
+$as_echo_n "checking for libcouchbase/couchbase.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <libcouchbase/couchbase.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
+
+ if test "x$ac_cv_header_libcouchbase_couchbase_h" != "xyes"; then
+ have_couchbase="no"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libcouchbase headers not found. Use --with-libcouchbase-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: libcouchbase headers not found. Use --with-libcouchbase-include-dir=<path>." >&2;}
+ fi
+
+
+ smart_try_dir="$libcouchbase_lib_dir"
+
+
+sm_lib_safe=`echo "couchbase" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "lcb_get_version" | 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 lcb_get_version in -lcouchbase in $try" >&5
+$as_echo_n "checking for lcb_get_version in -lcouchbase in $try... " >&6; }
+ LIBS="-lcouchbase $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char lcb_get_version();
+int
+main ()
+{
+lcb_get_version()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcouchbase"
+ 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 lcb_get_version in -lcouchbase" >&5
+$as_echo_n "checking for lcb_get_version in -lcouchbase... " >&6; }
+ LIBS="-lcouchbase $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char lcb_get_version();
+int
+main ()
+{
+lcb_get_version()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcouchbase"
+ { $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=libcouchbase${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=libcouchbase.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 lcb_get_version in -lcouchbase in $try" >&5
+$as_echo_n "checking for lcb_get_version in -lcouchbase in $try... " >&6; }
+ LIBS="-lcouchbase $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char lcb_get_version();
+int
+main ()
+{
+lcb_get_version()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcouchbase"
+ 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_couchbase_lcb_get_version" != "xyes"
+ then
+ have_couchbase="no"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libcouchbase libraries not found. Use --with-libcouchbase-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: libcouchbase libraries not found. Use --with-libcouchbase-lib-dir=<path>." >&2;}
+ fi
+
+ if test "x$have_couchbase" != "xyes"; then
+ fail="$fail json-c"
+ fi
+
+ if test "x$have_couchbase" = "xno"; then
+ fail="$fail libcouchbase"
+ fi
+
+
+ targetname=rlm_couchbase
+else
+ targetname=
+ echo \*\*\* module rlm_couchbase is disabled.
+fi
+
+if test x"$fail" != x""; then
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_couchbase to disable it explicitly." "$LINENO" 5
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_couchbase." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_couchbase." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_couchbase requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_couchbase requires: $fail." >&2;};
+ targetname=""
+ fi
+fi
+
+mod_ldflags="${SMART_LIBS}"
+mod_cflags="${SMART_CFLAGS}"
+
+
+
+
+
+
+ unset ac_cv_env_LIBS_set
+ unset ac_cv_env_LIBS_value
+
+ ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = "\a"
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_tt"; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = "\a"
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+ } >"$ac_tmp/config.h" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$ac_tmp/config.h" "$ac_file" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
+ fi
+ ;;
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
--- /dev/null
+AC_PREREQ([2.53])
+AC_INIT(rlm_couchbase.c)
+AC_REVISION($Revision$)
+AC_DEFUN(modname,[rlm_couchbase])
+AC_CONFIG_HEADER(config.h)
+
+if test x$with_[]modname != xno; then
+
+ AC_PROG_CC
+ AC_PROG_CPP
+
+ dnl put configuration checks here.
+ dnl set $fail to what's missing, on fatal errors.
+ dnl use AC_MSG_WARN() on important messages.
+
+ dnl ############################################################
+ dnl # Check for json-c
+ dnl ############################################################
+
+ dnl extra argument: --with-jsonc-include-dir=DIR
+ jsonc_include_dir=
+ AC_ARG_WITH(jsonc-include-dir,
+ [AS_HELP_STRING([--with-jsonc-include-dir=DIR],
+ [Directory where the json-c includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need jsonc-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ jsonc_include_dir="$withval"
+ ;;
+ esac])
+
+ dnl extra argument: --with-jsonc-lib-dir=DIR
+ jsonc_lib_dir=
+ AC_ARG_WITH(jsonc-lib-dir,
+ [AS_HELP_STRING([--with-jsonc-lib-dir=DIR],
+ [Directory where the json-c libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need jsonc-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ jsonc_lib_dir="$withval"
+ ;;
+ esac])
+
+ dnl extra argument: --with-jsonc-dir=DIR
+ AC_ARG_WITH(jsonc-dir,
+ [AS_HELP_STRING([--with-jsonc-dir=DIR],
+ [Base directory where json-c is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need json-c-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ jsonc_lib_dir="$withval/lib"
+ jsonc_include_dir="$withval/include"
+ ;;
+ esac])
+
+ dnl ############################################################
+ dnl # Check for json-c header files
+ dnl ############################################################
+
+ have_json="yes"
+ smart_try_dir="$jsonc_include_dir"
+ FR_SMART_CHECK_INCLUDE([json/json.h])
+ if test "x$ac_cv_header_json_json_h" != "xyes"; then
+ have_json="no"
+ AC_MSG_WARN([json-c headers not found. Use --with-jsonc-include-dir=<path>.])
+ fi
+
+ dnl ############################################################
+ dnl # Check for json-c libraries
+ dnl ############################################################
+
+ smart_try_dir="$jsonc_lib_dir"
+ dnl # Use a json-c specific function which is only
+ dnl # available in newer versions.
+ FR_SMART_CHECK_LIB([json-c], [json_c_version])
+ if test "x$ac_cv_lib_json_c_json_c_version" != "xyes"
+ then
+ dnl # Use a function which is included in legacy versions
+ dnl # but which may be available in other json libraries
+ FR_SMART_CHECK_LIB([json], [json_tokener_new])
+ if test "x$ac_cv_lib_json_json_tokener_new" != "xyes"
+ then
+ have_json="no"
+ fi
+ fi
+
+ if test "x$have_json" = "xyes"; then
+ dnl # Ensure we use the library we just found the rest of the checks
+ LDFLAGS="$SMART_LIBS"
+
+ dnl # Add any optional functions here
+ AC_CHECK_FUNCS(\
+ json_c_version \
+ json_object_get_string_len \
+ json_object_object_get_ex \
+ json_object_new_int64 \
+ json_tokener_parse_verbose \
+ json_tokener_error_desc \
+ json_tokener_get_error
+ )
+ else
+ fail="$fail json-c"
+ fi
+
+ dnl ############################################################
+ dnl # Check for libcouchbase
+ dnl ############################################################
+
+ dnl extra argument: --with-libcouchbase-include-dir=DIR
+ libcouchbase_include_dir=
+ AC_ARG_WITH(libcouchbase-include-dir,
+ [AS_HELP_STRING([--with-libcouchbase-include-dir=DIR],
+ [Directory where the libcouchbase includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need libcouchbase-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ libcouchbase_include_dir="$withval"
+ ;;
+ esac])
+
+ dnl extra argument: --with-libcouchbase-lib-dir=DIR
+ libcouchbase_lib_dir=
+ AC_ARG_WITH(libcouchbase-lib-dir,
+ [AS_HELP_STRING([--with-libcouchbase-lib-dir=DIR],
+ [Directory where the libcouchbase libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need libcouchbase-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ libcouchbase_lib_dir="$withval"
+ ;;
+ esac])
+
+ dnl extra argument: --with-libcouchbase-dir=DIR
+ AC_ARG_WITH(libcouchbase-dir,
+ [AS_HELP_STRING([--with-libcouchbase-dir=DIR],
+ [Base directory where libcouchbase is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need libcouchbase-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ libcouchbase_lib_dir="$withval/lib"
+ libcouchbase_include_dir="$withval/include"
+ ;;
+ esac])
+
+ dnl ############################################################
+ dnl # Check for libcouchbase header files
+ dnl ############################################################
+
+ have_couchbase="yes"
+ smart_try_dir="$libcouchbase_include_dir"
+ FR_SMART_CHECK_INCLUDE([libcouchbase/couchbase.h])
+ if test "x$ac_cv_header_libcouchbase_couchbase_h" != "xyes"; then
+ have_couchbase="no"
+ AC_MSG_WARN([libcouchbase headers not found. Use --with-libcouchbase-include-dir=<path>.])
+ fi
+
+ dnl ############################################################
+ dnl # Check for libcouchbase libraries
+ dnl ############################################################
+
+ smart_try_dir="$libcouchbase_lib_dir"
+ FR_SMART_CHECK_LIB([couchbase], [lcb_get_version])
+ if test "x$ac_cv_lib_couchbase_lcb_get_version" != "xyes"
+ then
+ have_couchbase="no"
+ AC_MSG_WARN([libcouchbase libraries not found. Use --with-libcouchbase-lib-dir=<path>.])
+ fi
+
+ if test "x$have_couchbase" != "xyes"; then
+ fail="$fail json-c"
+ fi
+
+ if test "x$have_couchbase" = "xno"; then
+ fail="$fail libcouchbase"
+ fi
+
+ dnl ############################################################
+ dnl # Checks done - set targetname
+ dnl ############################################################
+
+ targetname=modname
+else
+ targetname=
+ echo \*\*\* module modname is disabled.
+fi
+
+dnl Don't change this section.
+if test x"$fail" != x""; then
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ AC_MSG_ERROR([set --without-]modname[ to disable it explicitly.])
+ else
+ AC_MSG_WARN([silently not building ]modname[.])
+ AC_MSG_WARN([FAILURE: ]modname[ requires: $fail.]);
+ targetname=""
+ fi
+fi
+
+mod_ldflags="${SMART_LIBS}"
+mod_cflags="${SMART_CFLAGS}"
+
+AC_SUBST(mod_cflags)
+AC_SUBST(mod_ldflags)
+
+AC_SUBST(targetname)
+AC_OUTPUT(all.mk)
--- /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
+ */
+
+/*
+ * $Id$
+ *
+ * @brief Wrapper functions around the libcouchbase Couchbase client driver.
+ * @file couchbase.c
+ *
+ * @copyright 2013-2014 Aaron Hurt <ahurt@anbcs.com>
+ */
+
+RCSID("$Id$");
+
+#include <freeradius-devel/radiusd.h>
+
+#include <libcouchbase/couchbase.h>
+#include <json/json.h>
+
+#include "couchbase.h"
+#include "jsonc_missing.h"
+
+/* general couchbase error callback */
+void couchbase_error_callback(lcb_t instance, lcb_error_t error, const char *errinfo) {
+ /* log error */
+ ERROR("rlm_couchbase: (error_callback) %s (0x%x), %s", lcb_strerror(instance, error), error, errinfo);
+}
+
+/* couchbase value store callback */
+void couchbase_store_callback(lcb_t instance, const void *cookie, lcb_storage_t operation, lcb_error_t error, const lcb_store_resp_t *resp) {
+ if (error != LCB_SUCCESS) {
+ /* log error */
+ ERROR("rlm_couchbase: (store_callback) %s (0x%x)", lcb_strerror(instance, error), error);
+ }
+ /* silent compiler */
+ (void)cookie;
+ (void)operation;
+ (void)resp;
+}
+
+/* couchbase value get callback */
+void couchbase_get_callback(lcb_t instance, const void *cookie, lcb_error_t error, const lcb_get_resp_t *resp) {
+ cookie_u cu; /* union of const and non const pointers */
+ cu.cdata = cookie; /* set const union member to cookie passed from couchbase */
+ cookie_t *c = (cookie_t *) cu.data; /* set our cookie struct using non-const member */
+ const char *bytes = resp->v.v0.bytes; /* the payload of this chunk */
+ lcb_size_t nbytes = resp->v.v0.nbytes; /* length of this data chunk */
+
+ /* check error */
+ switch (error) {
+ case LCB_SUCCESS:
+ /* check for valid bytes */
+ if (bytes && nbytes > 1) {
+ /* debug */
+ DEBUG("rlm_couchbase: (get_callback) got %zu bytes", nbytes);
+ /* build json object */
+ c->jobj = json_tokener_parse_verbose(bytes, &c->jerr);
+ /* switch on current error status */
+ switch (c->jerr) {
+ case json_tokener_success:
+ /* do nothing */
+ break;
+ default:
+ /* log error */
+ ERROR("rlm_couchbase: (get_callback) JSON Tokener error: %s", json_tokener_error_desc(c->jerr));
+ break;
+ }
+ }
+ break;
+ case LCB_KEY_ENOENT:
+ /* ignored */
+ DEBUG("rlm_couchbase: (get_callback) key does not exist");
+ break;
+ default:
+ /* log error */
+ ERROR("rlm_couchbase: (get_callback) %s (0x%x)", lcb_strerror(instance, error), error);
+ break;
+ }
+}
+
+/* connect to couchbase */
+lcb_t couchbase_init_connection(const char *host, const char *bucket, const char *pass) {
+ lcb_t instance; /* couchbase instance */
+ lcb_error_t error; /* couchbase command return */
+ struct lcb_create_st options; /* init create struct */
+
+ /* init options */
+ memset(&options, 0, sizeof(options));
+
+ /* assign couchbase create options */
+ options.v.v0.host = host;
+ options.v.v0.bucket = bucket;
+
+ /* assign user and password if they were both passed */
+ if (bucket != NULL && pass != NULL) {
+ options.v.v0.user = bucket;
+ options.v.v0.passwd = pass;
+ }
+
+ /* create couchbase connection instance */
+ if ((error = lcb_create(&instance, &options)) != LCB_SUCCESS) {
+ /* log error and return */
+ ERROR("rlm_couchbase: failed to create couchbase instance: %s (0x%x)", lcb_strerror(NULL, error), error);
+ /* return instance */
+ return instance;
+ }
+
+ /* initiate connection */
+ if ((error = lcb_connect(instance)) == LCB_SUCCESS) {
+ /* set general method callbacks */
+ lcb_set_error_callback(instance, couchbase_error_callback);
+ lcb_set_get_callback(instance, couchbase_get_callback);
+ lcb_set_store_callback(instance, couchbase_store_callback);
+ /* wait on connection */
+ lcb_wait(instance);
+ } else {
+ /* log error */
+ ERROR("rlm_couchbase: Failed to initiate couchbase connection: %s (0x%x)", lcb_strerror(NULL, error), error);
+ }
+
+ /* return instance */
+ return instance;
+}
+
+/* store document/key in couchbase */
+lcb_error_t couchbase_set_key(lcb_t instance, const char *key, const char *document, int expire) {
+ lcb_error_t error; /* couchbase command return */
+ lcb_store_cmd_t cmd; /* store command stuct */
+ const lcb_store_cmd_t *commands[1]; /* store commands array */
+
+ /* init commands */
+ commands[0] = &cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ /* populate command struct */
+ cmd.v.v0.key = key;
+ cmd.v.v0.nkey = strlen(cmd.v.v0.key);
+ cmd.v.v0.bytes = document;
+ cmd.v.v0.nbytes = strlen(cmd.v.v0.bytes);
+ cmd.v.v0.exptime = expire;
+ cmd.v.v0.operation = LCB_SET;
+
+ /* store key/document in couchbase */
+ if ((error = lcb_store(instance, NULL, 1, commands)) == LCB_SUCCESS) {
+ /* enter event loop on success */
+ lcb_wait(instance);
+ }
+
+ /* return error */
+ return error;
+}
+
+/* pull document from couchbase by key */
+lcb_error_t couchbase_get_key(lcb_t instance, const void *cookie, const char *key) {
+ lcb_error_t error; /* couchbase command return */
+ lcb_get_cmd_t cmd; /* get command struct */
+ const lcb_get_cmd_t *commands[1]; /* get commands array */
+
+ /* init commands */
+ commands[0] = &cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ /* populate command struct */
+ cmd.v.v0.key = key;
+ cmd.v.v0.nkey = strlen(cmd.v.v0.key);
+
+ /* get document */
+ if ((error = lcb_get(instance, cookie, 1, commands)) == LCB_SUCCESS) {
+ /* enter event loop on success */
+ lcb_wait(instance);
+ }
+
+ /* return error */
+ return error;
+}
--- /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
+ */
+
+/*
+ * $Id$
+ *
+ * @brief Couchbase wrapper function prototypes and datatypes.
+ * @file couchbase.h
+ *
+ * @copyright 2013-2014 Aaron Hurt <ahurt@anbcs.com>
+ */
+
+#ifndef _couchbase_h_
+#define _couchbase_h_
+
+RCSIDH(couchbase_h, "$Id$");
+
+#include <libcouchbase/couchbase.h>
+#include <json/json.h>
+
+/* struct to hold cookie data for couchbase callbacks */
+typedef struct cookie_t {
+ json_object *jobj; /* json object */
+ json_tokener *jtok; /* json tokener */
+ enum json_tokener_error jerr; /* tokener error */
+} cookie_t;
+
+/* union of const and non const pointers */
+typedef union cookie_u {
+ const void *cdata;
+ void *data;
+} cookie_u;
+
+/* general error callback */
+void couchbase_error_callback(lcb_t instance, lcb_error_t error, const char *errinfo);
+
+/* store a key/document in couchbase */
+void couchbase_store_callback(lcb_t instance, const void *cookie, lcb_storage_t operation,
+ lcb_error_t error, const lcb_store_resp_t *item);
+
+/* get a document by key from couchbase */
+void couchbase_get_callback(lcb_t instance, const void *cookie, lcb_error_t error,
+ const lcb_get_resp_t *item);
+
+/* create a couchbase instance and connect to the cluster */
+lcb_t couchbase_init_connection(const char *host, const char *bucket, const char *pass);
+
+/* store document/key in couchbase */
+lcb_error_t couchbase_set_key(lcb_t instance, const char *key, const char *document, int expire);
+
+/* pull document from couchbase by key */
+lcb_error_t couchbase_get_key(lcb_t instance, const void *cookie, const char *key);
+
+#endif /* _couchbase_h_ */
--- /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
+ */
+
+/*
+ * $Id$
+ *
+ * @brief Workarounds for missing functions in older json-c libraries.
+ * @file json_missing.c
+ *
+ * @copyright 2013-2014 Aaron Hurt <ahurt@anbcs.com>
+ */
+
+RCSID("$Id$");
+
+#include <string.h>
+
+#include "jsonc_missing.h"
+
+#ifndef HAVE_JSON_OBJECT_GET_STRING_LEN
+int json_object_get_string_len(json_object *obj) {
+ if (json_object_get_type(obj) != json_type_string)
+ return 0;
+ return (int)strlen(json_object_to_json_string(obj));
+}
+#endif
+
+#ifndef HAVE_JSON_OBJECT_OBJECT_GET_EX
+int json_object_object_get_ex(struct json_object *jso, const char *key, struct json_object **value) {
+ struct json_object *jobj;
+
+ if ((jso == NULL) || (key == NULL)) return 0;
+ if (value != NULL) *value = NULL;
+
+ switch (json_object_get_type(jso)) {
+ case json_type_object:
+ jobj = json_object_object_get(jso, key);
+ if (jobj == NULL) return 0;
+
+ if (value != NULL) *value = jobj;
+ return 1;
+
+ default:
+ if (value != NULL) *value = NULL;
+ return 0;
+ }
+}
+#endif
+
+#ifndef HAVE_JSON_TOKENER_PARSE_VERBOSE
+struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error) {
+ struct json_tokener* tok;
+ struct json_object* obj;
+
+ tok = json_tokener_new();
+ if (!tok)
+ return NULL;
+ obj = json_tokener_parse_ex(tok, str, -1);
+ *error = tok->err;
+ if(tok->err != json_tokener_success) {
+ if (obj != NULL)
+ json_object_put(obj);
+ obj = NULL;
+ }
+
+ json_tokener_free(tok);
+ return obj;
+}
+#endif
+
+#ifndef HAVE_JSON_TOKENER_GET_ERROR
+enum json_tokener_error json_tokener_get_error(json_tokener *tok) {
+ return tok->err;
+}
+#endif
+
+#ifndef HAVE_JSON_TOKENER_ERROR_DESC
+const char *json_tokener_error_desc(enum json_tokener_error jerr) {
+ int jerr_int = (int)jerr;
+ if (json_tokener_errors[jerr_int] == NULL)
+ return "Unknown error, invalid json_tokener_error value passed to json_tokener_error_desc()";
+ return json_tokener_errors[jerr_int];
+}
+#endif
--- /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
+ */
+
+/*
+ * $Id$
+ *
+ * @brief Function prototypes for missing functions in older json-c libraries.
+ * @file json_missing.h
+ *
+ * @copyright 2013-2014 Aaron Hurt <ahurt@anbcs.com>
+ */
+
+#ifndef _jsonc_missing_h_
+#define _jsonc_missing_h_
+
+RCSIDH(jsonc_missing_h, "$Id$");
+
+#include <json/json.h>
+
+#include "config.h"
+
+#ifndef HAVE_JSON_OBJECT_OBJECT_GET_EX
+ #include <json/json_object_private.h>
+#endif
+
+#ifndef HAVE_JSON_OBJECT_GET_STRING_LEN
+ int json_object_get_string_len(struct json_object *obj);
+#endif
+
+#ifndef HAVE_JSON_OBJECT_OBJECT_GET_EX
+ int json_object_object_get_ex(struct json_object* jso, const char *key, struct json_object **value);
+#endif
+
+#ifndef HAVE_JSON_TOKENER_PARSE_VERBOSE
+ struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error);
+#endif
+
+#ifndef HAVE_JSON_TOKENER_ERROR_DESC
+ const char *json_tokener_error_desc(enum json_tokener_error jerr);
+#endif
+
+#ifndef HAVE_JSON_TOKENER_GET_ERROR
+ enum json_tokener_error json_tokener_get_error(json_tokener *tok);
+#endif
+
+/* correct poor const handling within json-c library */
+#ifdef json_object_object_foreach
+ #undef json_object_object_foreach
+#endif
+
+/* redefine with correct handling of const pointers */
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+ #define json_object_object_foreach(obj, key, val) \
+ char *key; struct json_object *val; \
+ union ctn_u {const void *cdata; void *data; } ctn; \
+ for (struct lh_entry *entry = json_object_get_object(obj)->head; \
+ ({ if (entry) { key = (char *)entry->k; ctn.cdata = entry->v; \
+ val = (struct json_object *)ctn.data; }; entry; }); \
+ entry = entry->next)
+#else /* ANSI C or MSC */
+ #define json_object_object_foreach(obj,key,val) \
+ char *key; struct json_object *val; struct lh_entry *entry; \
+ union ctn_u {const void *cdata; void *data; } ctn; \
+ for (entry = json_object_get_object(obj)->head; \
+ (entry ? (key = (char *)entry->k, ctn.cdata = entry->v, \
+ val = (struct json_object *)ctn.data, entry) : 0); entry = entry->next)
+#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) */
+
+
+/* correct poor const handling within json-c library */
+#ifdef json_object_object_foreachC
+ #undef json_object_object_foreachC
+#endif
+
+/* redefine with correct const handling */
+#define json_object_object_foreachC(obj,iter) \
+ union ctn_u {const void *cdata; void *data; } ctn; \
+ for (iter.entry = json_object_get_object(obj)->head; \
+ (iter.entry ? (iter.key = (char *)iter.entry->k, \
+ ctn.cdata = iter.entry->v, iter.val = (struct json_object*) ctn.data, iter.entry) : 0); \
+ iter.entry = iter.entry->next)
+
+#endif /* _jsonc_missing_h_ */
--- /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
+ */
+
+/*
+ * $Id$
+ *
+ * @brief Utillity functions used in the module.
+ * @file mod.c
+ *
+ * @copyright 2013-2014 Aaron Hurt <ahurt@anbcs.com>
+ */
+
+RCSID("$Id$");
+
+#include <freeradius-devel/radiusd.h>
+
+#include <libcouchbase/couchbase.h>
+#include <json/json.h>
+
+#include "mod.h"
+#include "couchbase.h"
+#include "jsonc_missing.h"
+
+/* create new connection pool handle */
+void *mod_conn_create(void *instance) {
+ rlm_couchbase_t *inst = instance; /* module instance pointer */
+ rlm_couchbase_handle_t *chandle = NULL; /* connection handle pointer */
+ cookie_t *cookie = NULL; /* couchbase cookie */
+ lcb_t cb_inst; /* couchbase connection instance */
+ lcb_error_t cb_error = LCB_SUCCESS; /* couchbase error status */
+
+ /* create instance */
+ cb_inst = couchbase_init_connection(inst->server, inst->bucket, inst->password);
+
+ /* check couchbase instance status */
+ if ((cb_error = lcb_get_last_error(cb_inst)) != LCB_SUCCESS) {
+ ERROR("rlm_couchbase: failed to initiate couchbase connection: %s (0x%x)", lcb_strerror(NULL, cb_error), cb_error);
+ /* destroy/free couchbase instance */
+ lcb_destroy(cb_inst);
+ /* fail */
+ return NULL;
+ }
+
+ /* allocate memory for couchbase connection instance abstraction */
+ chandle = talloc_zero(inst, rlm_couchbase_handle_t);
+ cookie = talloc_zero(chandle, cookie_t);
+
+ /* initialize cookie error holder */
+ cookie->jerr = json_tokener_success;
+
+ /* populate handle with allocated structs */
+ chandle->cookie = cookie;
+ chandle->handle = cb_inst;
+
+ /* return handle struct */
+ return chandle;
+}
+
+/* verify valid couchbase connection handle */
+int mod_conn_alive(UNUSED void *instance, void *handle) {
+ rlm_couchbase_handle_t *chandle = handle; /* connection handle pointer */
+ lcb_t cb_inst = chandle->handle; /* couchbase instance */
+ lcb_error_t cb_error = LCB_SUCCESS; /* couchbase error status */
+
+ /* attempt to get server list */
+ const char *const *servers = lcb_get_server_list(cb_inst);
+
+ /* check error state and server list return */
+ if (((cb_error = lcb_get_last_error(cb_inst)) != LCB_SUCCESS) || (servers == NULL)) {
+ /* log error */
+ ERROR("rlm_couchbase: failed to get couchbase server topology: %s (0x%x)", lcb_strerror(NULL, cb_error), cb_error);
+ /* return false */
+ return false;
+ }
+ return true;
+}
+
+/* free couchbase instance handle and any additional context memory */
+int mod_conn_delete(UNUSED void *instance, void *handle) {
+ rlm_couchbase_handle_t *chandle = handle; /* connection instance handle */
+ lcb_t cb_inst = chandle->handle; /* couchbase instance */
+
+ /* destroy/free couchbase instance */
+ lcb_destroy(cb_inst);
+
+ /* free handle */
+ talloc_free(chandle);
+
+ /* return */
+ return true;
+}
+
+/* build json object for mapping radius attributes to json elements */
+int mod_build_attribute_element_map(CONF_SECTION *conf, void *instance) {
+ rlm_couchbase_t *inst = instance; /* our module instance */
+ CONF_SECTION *cs; /* module config section */
+ CONF_ITEM *ci; /* config item */
+ CONF_PAIR *cp; /* conig pair */
+ const char *attribute, *element; /* attribute and element names */
+
+ /* find map section */
+ cs = cf_section_sub_find(conf, "map");
+
+ /* check section */
+ if (!cs) {
+ ERROR("rlm_couchbase: failed to find 'map' section in config");
+ /* fail */
+ return -1;
+ }
+
+ /* create attribute map object */
+ inst->map = json_object_new_object();
+
+ /* parse update section */
+ for (ci = cf_item_find_next(cs, NULL); ci != NULL; ci = cf_item_find_next(cs, ci)) {
+ /* validate item */
+ if (!cf_item_is_pair(ci)) {
+ ERROR("rlm_couchbase: failed to parse invalid item in 'map' section");
+ /* free map */
+ if (inst->map) {
+ json_object_put(inst->map);
+ }
+ /* fail */
+ return -1;
+ }
+
+ /* get value pair from item */
+ cp = cf_itemtopair(ci);
+
+ /* get pair name (element name) */
+ element = cf_pair_attr(cp);
+
+ /* get pair value (attribute name) */
+ attribute = cf_pair_value(cp);
+
+ /* add pair name and value */
+ json_object_object_add(inst->map, attribute, json_object_new_string(element));
+
+ /* debugging */
+ DEBUG("rlm_couchbase: added attribute '%s' to element '%s' map to object", attribute, element);
+ }
+
+ /* debugging */
+ DEBUG("rlm_couchbase: built attribute to element map %s", json_object_to_json_string(inst->map));
+
+ /* return */
+ return 0;
+}
+
+/* map free radius attribute to user defined json element name */
+int mod_attribute_to_element(const char *name, json_object *map, void *buf) {
+ json_object *jval; /* json object values */
+
+ /* clear buffer */
+ memset((char *) buf, 0, MAX_KEY_SIZE);
+
+ /* attempt to map attribute */
+ if (json_object_object_get_ex(map, name, &jval)) {
+ int length; /* json value length */
+ /* get value length */
+ length = json_object_get_string_len(jval);
+ /* check buffer size */
+ if (length > MAX_KEY_SIZE -1) {
+ /* oops ... this value is bigger than our buffer ... error out */
+ ERROR("rlm_couchbase: json map value larger than MAX_KEY_SIZE - %d", MAX_KEY_SIZE);
+ /* return fail */
+ return -1;
+ } else {
+ /* copy string value to buffer */
+ strncpy(buf, json_object_get_string(jval), length);
+ /* return good */
+ return 0;
+ }
+ }
+
+ /* debugging */
+ DEBUG("rlm_couchbase: skipping attribute with no map entry - %s", name);
+
+ /* default return */
+ return -1;
+}
+
+/* inject value pairs into given request
+ * that are defined in the passed json object
+ */
+void *mod_json_object_to_value_pairs(json_object *json, const char *section, REQUEST *request) {
+ json_object *jobj, *jval, *jop; /* json object pointers */
+ TALLOC_CTX *ctx; /* talloc context for pairmake */
+ VALUE_PAIR *vp, **ptr; /* value pair and value pair pointer for pairmake */
+
+ /* assign ctx and vps for pairmake based on section */
+ if (strcmp(section, "config") == 0) {
+ ctx = request;
+ ptr = &(request->config_items);
+ } else if (strcmp(section, "reply") == 0) {
+ ctx = request->reply;
+ ptr = &(request->reply->vps);
+ } else {
+ /* log error - this shouldn't happen */
+ RERROR("invalid section passed for pairmake");
+ /* return */
+ return NULL;
+ }
+
+ /* get config payload */
+ if (json_object_object_get_ex(json, section, &jobj)) {
+ /* make sure we have the correct type */
+ if (!json_object_is_type(jobj, json_type_object)) {
+ /* log error */
+ RERROR("invalid json type for '%s' section - sections must be json objects", section);
+ /* reuturn */
+ return NULL;
+ }
+ /* loop through object */
+ json_object_object_foreach(jobj, attribute, json_vp) {
+ /* check for appropriate type in value and op */
+ if (!json_object_is_type(json_vp, json_type_object)) {
+ /* log error */
+ RERROR("invalid json type for '%s' attribute - attributes must be json objects", attribute);
+ /* return */
+ return NULL;
+ }
+ /* debugging */
+ RDEBUG("parsing '%s' attribute: %s => %s", section, attribute, json_object_to_json_string(json_vp));
+ /* create pair from json object */
+ if (json_object_object_get_ex(json_vp, "value", &jval) &&
+ json_object_object_get_ex(json_vp, "op", &jop)) {
+ /* make correct pairs based on json object type */
+ switch (json_object_get_type(jval)) {
+ case json_type_double:
+ case json_type_int:
+ case json_type_string:
+ /* debugging */
+ RDEBUG("adding '%s' attribute to '%s' section", attribute, section);
+ /* add pair */
+ vp = pairmake(ctx, ptr, attribute, json_object_get_string(jval),
+ fr_str2int(fr_tokens, json_object_get_string(jop), 0));
+ /* check pair */
+ if (!vp) {
+ RERROR("could not build value pair for '%s' attribute (%s)", attribute, fr_strerror());
+ /* return */
+ return NULL;
+ }
+ break;
+ case json_type_object:
+ case json_type_array:
+ /* log error - we want to handle these eventually */
+ RERROR("skipping unhandled nested json object or array value pair object");
+ break;
+ default:
+ /* log error - this shouldn't ever happen */
+ RERROR("skipping unhandled json type in value pair object");
+ break;
+ }
+ } else {
+ /* log error */
+ RERROR("failed to get 'value' or 'op' element for '%s' attribute", attribute);
+ }
+ }
+ /* return NULL */
+ return NULL;
+ }
+
+ /* debugging */
+ RDEBUG("couldn't find '%s' section in json object - not adding value pairs for this section", section);
+
+ /* return NULL */
+ return NULL;
+}
+
+/* convert freeradius value/pair to json object
+ * basic structure taken from freeradius function
+ * vp_prints_value_json in src/lib/print.c */
+json_object *mod_value_pair_to_json_object(REQUEST *request, VALUE_PAIR *vp) {
+ char value[255]; /* radius attribute value */
+
+ /* add this attribute/value pair to our json output */
+ if (!vp->da->flags.has_tag) {
+ switch (vp->da->type) {
+ case PW_TYPE_INTEGER:
+ case PW_TYPE_BYTE:
+ case PW_TYPE_SHORT:
+ /* skip if we have flags */
+ if (vp->da->flags.has_value) break;
+#ifdef HAVE_JSON_OBJECT_NEW_INT64
+ /* debug */
+ RDEBUG3("creating new int64 for unsigned 32 bit int/byte/short '%s'", vp->da->name);
+ /* return as 64 bit int - JSON spec does not support unsigned ints */
+ return json_object_new_int64(vp->vp_integer);
+#else
+ /* debug */
+ RDEBUG3("creating new int for unsigned 32 bit int/byte/short '%s'", vp->da->name);
+ /* return as 64 bit int - JSON spec does not support unsigned ints */
+ return json_object_new_int(vp->vp_integer);
+#endif
+ break;
+ case PW_TYPE_SIGNED:
+#ifdef HAVE_JSON_OBJECT_NEW_INT64
+ /* debug */
+ RDEBUG3("creating new int64 for signed 32 bit integer '%s'", vp->da->name);
+ /* return as 64 bit int - json-c represents all ints as 64 bits internally */
+ return json_object_new_int64(vp->vp_signed);
+#else
+ RDEBUG3("creating new int for signed 32 bit integer '%s'", vp->da->name);
+ /* return as signed int */
+ return json_object_new_int(vp->vp_signed);
+#endif
+ break;
+ case PW_TYPE_INTEGER64:
+#ifdef HAVE_JSON_OBJECT_NEW_INT64
+ /* debug */
+ RDEBUG3("creating new int64 for 64 bit integer '%s'", vp->da->name);
+ /* return as 64 bit int - because it is a 64 bit int */
+ return json_object_new_int64(vp->vp_integer64);
+#else
+ /* warning */
+ RWARN("skipping 64 bit integer attribute '%s' - please upgrade json-c to 0.10+", vp->da->name);
+#endif
+ break;
+ default:
+ /* silence warnings - do nothing */
+ break;
+ }
+ }
+
+ /* keep going if not set above */
+ switch (vp->da->type) {
+ case PW_TYPE_STRING:
+ /* debug */
+ RDEBUG3("assigning string '%s' as string", vp->da->name);
+ /* return string value */
+ return json_object_new_string(vp->vp_strvalue);
+ default:
+ /* debug */
+ RDEBUG3("assigning unhandled '%s' as string", vp->da->name);
+ /* get standard value */
+ vp_prints_value(value, sizeof(value), vp, 0);
+ /* return string value from above */
+ return json_object_new_string(value);
+ break;
+ }
+}
+
+/* check current value of start timestamp in json body and update if needed */
+int mod_ensure_start_timestamp(json_object *json, VALUE_PAIR *vps) {
+ json_object *jval; /* json object value */
+ struct tm tm; /* struct to hold event time */
+ time_t ts = 0; /* values to hold time in seconds */
+ VALUE_PAIR *vp; /* values to hold value pairs */
+ char value[255]; /* store radius attribute values and our timestamp */
+
+ /* get our current start timestamp from our json body */
+ if (json_object_object_get_ex(json, "startTimestamp", &jval) == 0) {
+ /* debugging ... this shouldn't ever happen */
+ DEBUG("rlm_couchbase: failed to find start timestamp in current json body");
+ /* return */
+ return -1;
+ }
+
+ /* check the value */
+ if (strcmp(json_object_get_string(jval), "null") != 0) {
+ /* debugging */
+ DEBUG("rlm_couchbase: start timestamp looks good - nothing to do");
+ /* already set - nothing else to do */
+ return 0;
+ }
+
+ /* get current event timestamp */
+ if ((vp = pairfind(vps, PW_EVENT_TIMESTAMP, 0, TAG_ANY)) != NULL) {
+ /* get seconds value from attribute */
+ ts = vp->vp_date;
+ } else {
+ /* debugging */
+ DEBUG("rlm_couchbase: failed to find event timestamp in current request");
+ /* return */
+ return -1;
+ }
+
+ /* clear value */
+ memset(value, 0, sizeof(value));
+
+ /* get elapsed session time */
+ if ((vp = pairfind(vps, PW_ACCT_SESSION_TIME, 0, TAG_ANY)) != NULL) {
+ /* calculate diff */
+ ts = (ts - vp->vp_integer);
+ /* calculate start time */
+ size_t length = strftime(value, sizeof(value), "%b %e %Y %H:%M:%S %Z", localtime_r(&ts, &tm));
+ /* check length */
+ if (length > 0) {
+ /* debugging */
+ DEBUG("rlm_couchbase: calculated start timestamp: %s", value);
+ /* store new value in json body */
+ json_object_object_add(json, "startTimestamp", json_object_new_string(value));
+ } else {
+ /* debugging */
+ DEBUG("rlm_couchbase: failed to format calculated timestamp");
+ /* return */
+ return -1;
+ }
+ }
+
+ /* default return */
+ return 0;
+}
--- /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
+ */
+
+/*
+ * $Id$
+ *
+ * @brief Function prototypes and datatypes used in the module.
+ * @file mod.h
+ *
+ * @copyright 2013-2014 Aaron Hurt <ahurt@anbcs.com>
+ */
+
+#ifndef _mod_h_
+#define _mod_h_
+
+RCSIDH(mod_h, "$Id$");
+
+#include <libcouchbase/couchbase.h>
+#include <json/json.h>
+
+#include "jsonc_missing.h"
+
+/* maximum size of a stored value */
+#define MAX_VALUE_SIZE 20480
+
+/* maximum length of a document key */
+#define MAX_KEY_SIZE 250
+
+/* configuration struct */
+typedef struct rlm_couchbase_t {
+ char const *acct_key; //!< Accounting document key.
+ char const *doctype; //!< Value of 'docType' element name.
+ char const *server_raw; //!< Raw server string before parsing.
+ char const *server; //!< Couchbase server list.
+ char const *bucket; //!< Couchbase bucket.
+ char const *password; //!< Couchbase bucket password.
+ uint32_t expire; //!< Document expire time in seconds.
+ const char *user_key; //!< User document key.
+ json_object *map; //!< Json object to hold user defined attribute map.
+ fr_connection_pool_t *pool; //!< Connection pool.
+} rlm_couchbase_t;
+
+/* connection pool handle struct */
+typedef struct rlm_couchbase_handle_t {
+ void *handle; //!< Real couchbase instance.
+ void *cookie; //!< Couchbase cookie.
+} rlm_couchbase_handle_t;
+
+/* define functions */
+void *mod_conn_create(void *instance);
+
+int mod_conn_alive(UNUSED void *instance, void *handle);
+
+int mod_conn_delete(UNUSED void *instance, void *handle);
+
+int mod_build_attribute_element_map(CONF_SECTION *conf, void *instance);
+
+int mod_attribute_to_element(const char *name, json_object *map, void *buf);
+
+void *mod_json_object_to_value_pairs(json_object *json, const char *section, REQUEST *request);
+
+json_object *mod_value_pair_to_json_object(REQUEST *request, VALUE_PAIR *vp);
+
+int mod_ensure_start_timestamp(json_object *json, VALUE_PAIR *vps);
+
+#endif /* _mod_h_ */
--- /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
+ */
+
+/*
+ * $Id$
+ *
+ * @brief Integrate FreeRADIUS with the Couchbase document database.
+ * @file rlm_couchbase.c
+ *
+ * @copyright 2013-2014 Aaron Hurt <ahurt@anbcs.com>
+ */
+
+RCSID("$Id$");
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <libcouchbase/couchbase.h>
+#include <json/json.h>
+
+#include "mod.h"
+#include "couchbase.h"
+#include "jsonc_missing.h"
+
+/**
+ * Module Configuration
+ */
+static const CONF_PARSER module_config[] = {
+ { "acct_key", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_couchbase_t, acct_key), "radacct_%{%{Acct-Unique-Session-Id}:-%{Acct-Session-Id}}" },
+ { "doctype", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_couchbase_t, doctype), "radacct" },
+ { "server", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_couchbase_t, server), NULL },
+ { "bucket", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_couchbase_t, bucket), NULL },
+ { "password", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_couchbase_t, password), NULL },
+ { "expire", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_couchbase_t, expire), 0 },
+ { "user_key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_couchbase_t, user_key), "raduser_%{md5:%{tolower:%{%{Stripped-User-Name}:-%{User-Name}}}}" },
+ {NULL, -1, 0, NULL, NULL} /* end the list */
+};
+
+/* initialize couchbase connection */
+static int mod_instantiate(CONF_SECTION *conf, void *instance) {
+ rlm_couchbase_t *inst = instance; /* our module instance */
+
+ {
+ char *server, *p;
+ size_t len, i;
+ bool sep = false;
+
+ len = talloc_array_length(inst->server_raw);
+ server = p = talloc_array(inst, char, len);
+ for (i = 0; i < len; i++) {
+ switch (inst->server_raw[i]) {
+ case '\t':
+ case ' ':
+ case ',':
+ /* Consume multiple separators occurring in sequence */
+ if (sep == true) continue;
+
+ sep = true;
+ *p++ = ';';
+ break;
+
+ default:
+ sep = false;
+ *p++ = inst->server_raw[i];
+ break;
+ }
+ }
+
+ *p = '\0';
+ inst->server = server;
+ }
+
+ /* setup item map */
+ if (mod_build_attribute_element_map(conf, inst) != 0) {
+ /* fail */
+ return -1;
+ }
+
+ /* initiate connection pool */
+ inst->pool = fr_connection_pool_init(conf, inst, mod_conn_create, mod_conn_alive, mod_conn_delete, NULL);
+
+ /* check connection pool */
+ if (!inst->pool) {
+ ERROR("rlm_couchbase: failed to initiate connection pool");
+ /* fail */
+ return -1;
+ }
+
+ /* return okay */
+ return 0;
+}
+
+/* authorize users via couchbase */
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request) {
+ rlm_couchbase_t *inst = instance; /* our module instance */
+ void *handle = NULL; /* connection pool handle */
+ char dockey[MAX_KEY_SIZE]; /* our document key */
+ lcb_error_t cb_error = LCB_SUCCESS; /* couchbase error holder */
+
+ /* assert packet as not null */
+ rad_assert(request->packet != NULL);
+
+ /* attempt to build document key */
+ if (radius_xlat(dockey, sizeof(dockey), request, inst->user_key, NULL, NULL) < 0) {
+ /* log error */
+ RERROR("could not find user key attribute (%s) in packet", inst->user_key);
+ /* return */
+ return RLM_MODULE_FAIL;
+ }
+
+ /* get handle */
+ handle = fr_connection_get(inst->pool);
+
+ /* check handle */
+ if (!handle) return RLM_MODULE_FAIL;
+
+ /* set handle pointer */
+ rlm_couchbase_handle_t *handle_t = handle;
+
+ /* set couchbase instance */
+ lcb_t cb_inst = handle_t->handle;
+
+ /* set cookie */
+ cookie_t *cookie = handle_t->cookie;
+
+ /* check cookie */
+ if (cookie) {
+ /* clear cookie */
+ memset(cookie, 0, sizeof(cookie_t));
+ } else {
+ /* log error */
+ RERROR("cookie not usable - possibly not allocated");
+ /* free connection */
+ if (handle) {
+ fr_connection_release(inst->pool, handle);
+ }
+ /* return */
+ return RLM_MODULE_FAIL;
+ }
+
+ /* reset cookie error status */
+ cookie->jerr = json_tokener_success;
+
+ /* fetch document */
+ cb_error = couchbase_get_key(cb_inst, cookie, dockey);
+
+ /* check error */
+ if (cb_error != LCB_SUCCESS || cookie->jerr != json_tokener_success || cookie->jobj == NULL) {
+ /* log error */
+ RERROR("failed to fetch document or parse return");
+ /* free json object */
+ if (cookie->jobj) {
+ json_object_put(cookie->jobj);
+ }
+ /* release handle */
+ if (handle) {
+ fr_connection_release(inst->pool, handle);
+ }
+ /* return */
+ return RLM_MODULE_FAIL;
+ }
+
+ /* debugging */
+ RDEBUG("parsed user document == %s", json_object_to_json_string(cookie->jobj));
+
+ /* inject config value pairs defined in this json oblect */
+ mod_json_object_to_value_pairs(cookie->jobj, "config", request);
+
+ /* inject reply value pairs defined in this json oblect */
+ mod_json_object_to_value_pairs(cookie->jobj, "reply", request);
+
+ /* free json object */
+ if (cookie->jobj) {
+ json_object_put(cookie->jobj);
+ }
+
+ /* release handle */
+ if (handle) {
+ fr_connection_release(inst->pool, handle);
+ }
+
+ /* return okay */
+ return RLM_MODULE_OK;
+}
+
+/* write accounting data to couchbase */
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request) {
+ rlm_couchbase_t *inst = instance; /* our module instance */
+ void *handle = NULL; /* connection pool handle */
+ VALUE_PAIR *vp; /* radius value pair linked list */
+ char dockey[MAX_KEY_SIZE]; /* our document key */
+ char document[MAX_VALUE_SIZE]; /* our document body */
+ char element[MAX_KEY_SIZE]; /* mapped radius attribute to element name */
+ int status = 0; /* account status type */
+ int docfound = 0; /* document found toggle */
+ lcb_error_t cb_error = LCB_SUCCESS; /* couchbase error holder */
+
+ /* assert packet as not null */
+ rad_assert(request->packet != NULL);
+
+ /* sanity check */
+ if ((vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY)) == NULL) {
+ /* log debug */
+ RDEBUG("could not find status type in packet");
+ /* return */
+ return RLM_MODULE_NOOP;
+ }
+
+ /* set status */
+ status = vp->vp_integer;
+
+ /* acknowledge the request but take no action */
+ if (status == PW_STATUS_ACCOUNTING_ON || status == PW_STATUS_ACCOUNTING_OFF) {
+ /* log debug */
+ RDEBUG("handling accounting on/off request without action");
+ /* return */
+ return RLM_MODULE_OK;
+ }
+
+ /* get handle */
+ handle = fr_connection_get(inst->pool);
+
+ /* check handle */
+ if (!handle) return RLM_MODULE_FAIL;
+
+ /* set handle pointer */
+ rlm_couchbase_handle_t *handle_t = handle;
+
+ /* set couchbase instance */
+ lcb_t cb_inst = handle_t->handle;
+
+ /* set cookie */
+ cookie_t *cookie = handle_t->cookie;
+
+ /* check cookie */
+ if (cookie) {
+ /* clear cookie */
+ memset(cookie, 0, sizeof(cookie_t));
+ } else {
+ /* log error */
+ RERROR("cookie not usable - possibly not allocated");
+ /* free connection */
+ if (handle) {
+ fr_connection_release(inst->pool, handle);
+ }
+ /* return */
+ return RLM_MODULE_FAIL;
+ }
+
+ /* attempt to build document key */
+ if (radius_xlat(dockey, sizeof(dockey), request, inst->acct_key, NULL, NULL) < 0) {
+ /* log error */
+ RERROR("could not find accounting key attribute (%s) in packet", inst->acct_key);
+ /* release handle */
+ if (handle) {
+ fr_connection_release(inst->pool, handle);
+ }
+ /* return */
+ return RLM_MODULE_NOOP;
+ }
+
+ /* init cookie error status */
+ cookie->jerr = json_tokener_success;
+
+ /* attempt to fetch document */
+ cb_error = couchbase_get_key(cb_inst, cookie, dockey);
+
+ /* check error */
+ if (cb_error != LCB_SUCCESS || cookie->jerr != json_tokener_success) {
+ /* log error */
+ RERROR("failed to execute get request or parse returned json object");
+ /* free json object */
+ if (cookie->jobj) {
+ json_object_put(cookie->jobj);
+ }
+ } else {
+ /* check cookie json object */
+ if (cookie->jobj != NULL) {
+ /* set doc found */
+ docfound = 1;
+ /* debugging */
+ RDEBUG("parsed json body from couchbase: %s", json_object_to_json_string(cookie->jobj));
+ }
+ }
+
+ /* start json document if needed */
+ if (docfound != 1) {
+ /* debugging */
+ RDEBUG("document not found - creating new json document");
+ /* create new json object */
+ cookie->jobj = json_object_new_object();
+ /* set 'docType' element for new document */
+ json_object_object_add(cookie->jobj, "docType", json_object_new_string(inst->doctype));
+ /* set start and stop times ... ensure we always have these elements */
+ json_object_object_add(cookie->jobj, "startTimestamp", json_object_new_string("null"));
+ json_object_object_add(cookie->jobj, "stopTimestamp", json_object_new_string("null"));
+ }
+
+ /* status specific replacements for start/stop time */
+ switch (status) {
+ case PW_STATUS_START:
+ /* add start time */
+ if ((vp = pairfind(request->packet->vps, PW_EVENT_TIMESTAMP, 0, TAG_ANY)) != NULL) {
+ /* add to json object */
+ json_object_object_add(cookie->jobj, "startTimestamp", mod_value_pair_to_json_object(request, vp));
+ }
+ break;
+ case PW_STATUS_STOP:
+ /* add stop time */
+ if ((vp = pairfind(request->packet->vps, PW_EVENT_TIMESTAMP, 0, TAG_ANY)) != NULL) {
+ /* add to json object */
+ json_object_object_add(cookie->jobj, "stopTimestamp", mod_value_pair_to_json_object(request, vp));
+ }
+ /* check start timestamp and adjust if needed */
+ mod_ensure_start_timestamp(cookie->jobj, request->packet->vps);
+ break;
+ case PW_STATUS_ALIVE:
+ /* check start timestamp and adjust if needed */
+ mod_ensure_start_timestamp(cookie->jobj, request->packet->vps);
+ break;
+ default:
+ /* we shouldn't get here - free json object */
+ if (cookie->jobj) {
+ json_object_put(cookie->jobj);
+ }
+ /* release our connection handle */
+ if (handle) {
+ fr_connection_release(inst->pool, handle);
+ }
+ /* return without doing anything */
+ return RLM_MODULE_NOOP;
+ }
+
+ /* loop through pairs and add to json document */
+ for (vp = request->packet->vps; vp; vp = vp->next) {
+ /* map attribute to element */
+ if (mod_attribute_to_element(vp->da->name, inst->map, &element) == 0) {
+ /* debug */
+ RDEBUG("mapped attribute %s => %s", vp->da->name, element);
+ /* add to json object with mapped name */
+ json_object_object_add(cookie->jobj, element, mod_value_pair_to_json_object(request, vp));
+ }
+ }
+
+ /* make sure we have enough room in our document buffer */
+ if ((unsigned int) json_object_get_string_len(cookie->jobj) > sizeof(document) - 1) {
+ /* this isn't good */
+ RERROR("could not write json document - insufficient buffer space");
+ /* free json output */
+ if (cookie->jobj) {
+ json_object_put(cookie->jobj);
+ }
+ /* release handle */
+ if (handle) {
+ fr_connection_release(inst->pool, handle);
+ }
+ /* return */
+ return RLM_MODULE_FAIL;
+ } else {
+ /* copy json string to document */
+ strlcpy(document, json_object_to_json_string(cookie->jobj), sizeof(document));
+ /* free json output */
+ if (cookie->jobj) {
+ json_object_put(cookie->jobj);
+ }
+ }
+
+ /* debugging */
+ RDEBUG("setting '%s' => '%s'", dockey, document);
+
+ /* store document/key in couchbase */
+ cb_error = couchbase_set_key(cb_inst, dockey, document, inst->expire);
+
+ /* check return */
+ if (cb_error != LCB_SUCCESS) {
+ RERROR("failed to store document (%s): %s (0x%x)", dockey, lcb_strerror(NULL, cb_error), cb_error);
+ }
+
+ /* release handle */
+ if (handle) {
+ fr_connection_release(inst->pool, handle);
+ }
+
+ /* return */
+ return RLM_MODULE_OK;
+}
+
+/* free any memory we allocated */
+static int mod_detach(void *instance) {
+ rlm_couchbase_t *inst = instance; /* instance struct */
+
+ /* free json object attribute map */
+ if (inst->map) {
+ json_object_put(inst->map);
+ }
+
+ /* destroy connection pool */
+ if (inst->pool) {
+ fr_connection_pool_delete(inst->pool);
+ }
+
+ /* return okay */
+ return 0;
+}
+
+/* hook the module into freeradius */
+module_t rlm_couchbase = {
+ RLM_MODULE_INIT,
+ "rlm_couchbase",
+ RLM_TYPE_THREAD_SAFE, /* type */
+ sizeof(rlm_couchbase_t),
+ module_config,
+ mod_instantiate, /* instantiation */
+ mod_detach, /* detach */
+ {
+ NULL, /* authentication */
+ mod_authorize, /* authorization */
+ NULL, /* preaccounting */
+ mod_accounting, /* accounting */
+ NULL, /* checksimul */
+ NULL, /* pre-proxy */
+ NULL, /* post-proxy */
+ NULL /* post-auth */
+ },
+};
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
CPP C preprocessor
Use these variables to override the choices made by `configure' or to help
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=gdbm.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lgdbm"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lgdbm"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libgdbm${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libgdbm.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
--header=FILE[:TEMPLATE]
- instantiate the configuration header FILE
+ instantiate the configuration header FILE
Configuration files:
$config_files
GetOptions ('user=s' => \$user,
'match=s' => \$match,
'file=s' => \$filename,
- 'reset=i' => \$reset,
- 'help' => \$help,
+ 'reset=i' => \$reset,
+ 'help' => \$help,
'hours' => sub { $divisor = 3600 },
'minutes' => sub { $divisor = 60 },
'seconds' => sub { $divisor = 1 } );
#
if ($user ne '') {
if (defined($hash{$user})){
- print $user, "\t\t", int ( unpack('L',$hash{$user}) / $divisor), "\n";
+ print $user, "\t\t", int ( unpack('L',$hash{$user}) / $divisor), "\n";
if ($reset){
- my $uniqueid = (unpack('L A32',$hash{$user}))[1];
- $hash{$user} = pack('L A32',$reset * $divisor,$uniqueid);
- print $user, "\t\t", "Counter reset to ", $reset * $divisor, "\n";
- }
+ my $uniqueid = (unpack('L A32',$hash{$user}))[1];
+ $hash{$user} = pack('L A32',$reset * $divisor,$uniqueid);
+ print $user, "\t\t", "Counter reset to ", $reset * $divisor, "\n";
+ }
}else{
- print $user, "\t\t", "Not found\n";
+ print $user, "\t\t", "Not found\n";
}
undef $db;
# Print out the names...
print $key, "\t\t", int ( unpack('L',$hash{$key}) / $divisor), "\n";
if ($reset){
- my $uniqueid = (unpack('L A32',$hash{$key}))[1];
- $hash{$key} = pack('L A32',$reset * $divisor,$uniqueid);
- print $key, "\t\t", "Counter reset to ", $reset * $divisor, "\n";
+ my $uniqueid = (unpack('L A32',$hash{$key}))[1];
+ $hash{$key} = pack('L A32',$reset * $divisor,$uniqueid);
+ print $key, "\t\t", "Counter reset to ", $reset * $divisor, "\n";
}
}
undef $db;
char const *reply_name; /* Session-Timeout */
char const *service_type; /* Service-Type to search for */
- int cache_size;
+ uint32_t cache_size;
uint32_t service_val;
- int key_attr;
- int count_attr;
- int check_attr;
- int reply_attr;
- int dict_attr; /* attribute number for the counter. */
+ DICT_ATTR const *key_attr;
+ DICT_ATTR const *count_attr;
+ DICT_ATTR const *check_attr;
+ DICT_ATTR const *reply_attr;
+ DICT_ATTR const *dict_attr; /* attribute number for the counter. */
time_t reset_time; /* The time of the next reset. */
time_t last_reset; /* The time of the last reset. */
* buffer over-flows.
*/
static const CONF_PARSER module_config[] = {
- { "filename", PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED,
- offsetof(rlm_counter_t,filename), NULL, NULL },
- { "key", PW_TYPE_STRING_PTR | PW_TYPE_ATTRIBUTE,
- offsetof(rlm_counter_t,key_name), NULL, NULL },
- { "reset", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
- offsetof(rlm_counter_t,reset), NULL, NULL },
-
- { "count-attribute", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_counter_t,count_attribute), NULL, NULL },
- { "count_attribute", PW_TYPE_STRING_PTR | PW_TYPE_ATTRIBUTE,
- offsetof(rlm_counter_t,count_attribute), NULL, NULL },
-
- { "counter-name", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_counter_t,counter_name), NULL, NULL },
- { "counter_name", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
- offsetof(rlm_counter_t,counter_name), NULL, NULL },
-
- { "check-name", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_counter_t,check_name), NULL, NULL },
- { "check_name", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
- offsetof(rlm_counter_t,check_name), NULL, NULL },
-
- { "reply-name", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_counter_t,reply_name), NULL, NULL },
- { "reply_name", PW_TYPE_STRING_PTR | PW_TYPE_ATTRIBUTE,
- offsetof(rlm_counter_t,reply_name), NULL, NULL},
-
- { "allowed-servicetype", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_counter_t,service_type), NULL, NULL },
- { "allowed_service_type", PW_TYPE_STRING_PTR,
- offsetof(rlm_counter_t,service_type), NULL, NULL },
-
- { "cache-size", PW_TYPE_INTEGER | PW_TYPE_DEPRECATED,
- offsetof(rlm_counter_t,cache_size), NULL, NULL },
- { "cache_size", PW_TYPE_INTEGER,
- offsetof(rlm_counter_t,cache_size), NULL, "1000" },
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED, rlm_counter_t, filename), NULL },
+ { "key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_ATTRIBUTE, rlm_counter_t, key_name), NULL },
+ { "reset", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_counter_t, reset), NULL },
+
+ { "count-attribute", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_counter_t, count_attribute), NULL },
+ { "count_attribute", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_ATTRIBUTE, rlm_counter_t, count_attribute), NULL },
+
+ { "counter-name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_counter_t, counter_name), NULL },
+ { "counter_name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_counter_t, counter_name), NULL },
+
+ { "check-name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_counter_t, check_name), NULL },
+ { "check_name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_counter_t, check_name), NULL },
+
+ { "reply-name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_counter_t, reply_name), NULL },
+ { "reply_name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_ATTRIBUTE, rlm_counter_t, reply_name), NULL },
+
+ { "allowed-servicetype", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_counter_t, service_type), NULL },
+ { "allowed_service_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_counter_t, service_type), NULL },
+
+ { "cache-size", FR_CONF_OFFSET(PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, rlm_counter_t, cache_size), NULL },
+ { "cache_size", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_counter_t, cache_size), "1000" },
{ NULL, -1, 0, NULL, NULL }
};
/*
* Find the key attribute.
*/
- key_vp = pairfind(request, inst->key_attr, 0, TAG_ANY);
+ key_vp = pairfind_da(request, inst->key_attr, TAG_ANY);
if (!key_vp) {
return RLM_MODULE_NOOP;
}
time_datum.dptr = (char *) &inst->reset_time;
time_datum.dsize = sizeof(time_t);
- if (gdbm_store(inst->gdbm, key_datum, time_datum, GDBM_REPLACE) < 0){
- ERROR("rlm_counter: Failed storing data to %s: %s",
- inst->filename, gdbm_strerror(gdbm_errno));
+ if (gdbm_store(inst->gdbm, key_datum, time_datum, GDBM_REPLACE) < 0) {
+ ERROR("rlm_counter: Failed storing data to %s: %s", inst->filename, gdbm_strerror(gdbm_errno));
return RLM_MODULE_FAIL;
}
DEBUG2("rlm_counter: DEFAULT1 set to %u", (unsigned int) inst->reset_time);
time_datum.dptr = (char *) &inst->last_reset;
time_datum.dsize = sizeof(time_t);
- if (gdbm_store(inst->gdbm, key_datum, time_datum, GDBM_REPLACE) < 0){
- ERROR("rlm_counter: Failed storing data to %s: %s",
- inst->filename, gdbm_strerror(gdbm_errno));
+ if (gdbm_store(inst->gdbm, key_datum, time_datum, GDBM_REPLACE) < 0) {
+ ERROR("rlm_counter: Failed storing data to %s: %s", inst->filename, gdbm_strerror(gdbm_errno));
return RLM_MODULE_FAIL;
}
DEBUG2("rlm_counter: DEFAULT2 set to %u", (unsigned int) inst->last_reset);
inst->gdbm = gdbm_open(filename, sizeof(int), GDBM_NEWDB | GDBM_COUNTER_OPTS, 0600, NULL);
}
if (!inst->gdbm) {
- ERROR("rlm_counter: Failed to open file %s: %s",
- inst->filename, strerror(errno));
+ ERROR("rlm_counter: Failed to open file %s: %s", inst->filename, fr_syserror(errno));
return RLM_MODULE_FAIL;
}
- if (gdbm_setopt(inst->gdbm, GDBM_CACHESIZE, &cache_size,
- sizeof(cache_size)) == -1) {
+ if (gdbm_setopt(inst->gdbm, GDBM_CACHESIZE, &cache_size, sizeof(cache_size)) == -1) {
ERROR("rlm_counter: Failed to set cache size");
}
if (!inst->reset)
return -1;
- if (isdigit((int) inst->reset[0])){
+ if (isdigit((int) inst->reset[0])) {
len = strlen(inst->reset);
if (len == 0)
return -1;
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
rlm_counter_t *inst = instance;
- DICT_ATTR const *dattr;
+ DICT_ATTR const *da;
DICT_VALUE *dval;
ATTR_FLAGS flags;
time_t now;
cache_size = inst->cache_size;
- dattr = dict_attrbyname(inst->key_name);
- rad_assert(dattr != NULL);
- if (dattr->vendor != 0) {
- cf_log_err_cs(conf, "Configuration item 'key' cannot be a VSA");
- return -1;
- }
- inst->key_attr = dattr->attr;
+ da = dict_attrbyname(inst->key_name);
+ rad_assert(da != NULL);
+ inst->key_attr = da;
/*
* Discover the attribute number of the counter.
*/
- dattr = dict_attrbyname(inst->count_attribute);
- rad_assert(dattr != NULL);
- if (dattr->vendor != 0) {
- cf_log_err_cs(conf, "Configuration item 'count_attribute' cannot be a VSA");
- return -1;
- }
- inst->count_attr = dattr->attr;
+ da = dict_attrbyname(inst->count_attribute);
+ rad_assert(da != NULL);
+ inst->count_attr = da;
/*
* Discover the attribute number of the reply attribute.
*/
if (inst->reply_name != NULL) {
- dattr = dict_attrbyname(inst->reply_name);
- if (!dattr) {
- cf_log_err_cs(conf, "No such attribute %s",
- inst->reply_name);
+ da = dict_attrbyname(inst->reply_name);
+ if (!da) {
+ cf_log_err_cs(conf, "No such attribute %s", inst->reply_name);
return -1;
}
- if (dattr->type != PW_TYPE_INTEGER) {
- cf_log_err_cs(conf, "Reply attribute' %s' is not of type integer",
- inst->reply_name);
+ if (da->type != PW_TYPE_INTEGER) {
+ cf_log_err_cs(conf, "Reply attribute' %s' is not of type integer", inst->reply_name);
return -1;
}
- inst->reply_attr = dattr->attr;
+ inst->reply_attr = da;
+ } else {
+ inst->reply_attr = NULL;
}
/*
rad_assert(inst->counter_name && *inst->counter_name);
memset(&flags, 0, sizeof(flags));
if (dict_addattr(inst->counter_name, -1, 0, PW_TYPE_INTEGER, flags) < 0) {
- ERROR("rlm_counter: Failed to create counter attribute %s: %s",
- inst->counter_name, fr_strerror());
+ ERROR("rlm_counter: Failed to create counter attribute %s: %s", inst->counter_name, fr_strerror());
return -1;
}
- dattr = dict_attrbyname(inst->counter_name);
- if (!dattr) {
- cf_log_err_cs(conf, "Failed to find counter attribute %s",
- inst->counter_name);
+ da = dict_attrbyname(inst->counter_name);
+ if (!da) {
+ cf_log_err_cs(conf, "Failed to find counter attribute %s", inst->counter_name);
return -1;
}
- inst->dict_attr = dattr->attr;
- DEBUG2("rlm_counter: Counter attribute %s is number %d",
- inst->counter_name, inst->dict_attr);
+ inst->dict_attr = da;
+ DEBUG2("rlm_counter: Counter attribute %s is number %d", inst->counter_name, inst->dict_attr->attr);
/*
* Create a new attribute for the check item.
*/
rad_assert(inst->check_name && *inst->check_name);
if (dict_addattr(inst->check_name, -1, 0, PW_TYPE_INTEGER, flags) < 0) {
- ERROR("rlm_counter: Failed to create check attribute %s: %s",
- inst->counter_name, fr_strerror());
+ ERROR("rlm_counter: Failed to create check attribute %s: %s", inst->counter_name, fr_strerror());
return -1;
}
- dattr = dict_attrbyname(inst->check_name);
- if (!dattr) {
- ERROR("rlm_counter: Failed to find check attribute %s",
- inst->counter_name);
+ da = dict_attrbyname(inst->check_name);
+ if (!da) {
+ ERROR("rlm_counter: Failed to find check attribute %s", inst->counter_name);
return -1;
}
- inst->check_attr = dattr->attr;
+ inst->check_attr = da;
/*
* Find the attribute for the allowed protocol
*/
if (inst->service_type != NULL) {
if ((dval = dict_valbyname(PW_SERVICE_TYPE, 0, inst->service_type)) == NULL) {
- ERROR("rlm_counter: Failed to find attribute number for %s",
- inst->service_type);
+ ERROR("rlm_counter: Failed to find attribute number for %s", inst->service_type);
return -1;
}
inst->service_val = dval->value;
inst->reset_time = 0;
inst->last_reset = now;
- if (find_next_reset(inst,now) == -1){
- ERROR("rlm_counter: find_next_reset() returned -1. Exiting.");
+ if (find_next_reset(inst,now) == -1) {
+ ERROR("rlm_counter: find_next_reset() returned -1. Exiting");
return -1;
}
inst->gdbm = gdbm_open(filename, sizeof(int), GDBM_NEWDB | GDBM_COUNTER_OPTS, 0600, NULL);
}
if (!inst->gdbm) {
- ERROR("rlm_counter: Failed to open file %s: %s",
- inst->filename, strerror(errno));
+ ERROR("rlm_counter: Failed to open file %s: %s", inst->filename, fr_syserror(errno));
return -1;
}
- if (gdbm_setopt(inst->gdbm, GDBM_CACHESIZE, &cache_size,
- sizeof(cache_size)) == -1) {
+ if (gdbm_setopt(inst->gdbm, GDBM_CACHESIZE, &cache_size, sizeof(cache_size)) == -1) {
ERROR("rlm_counter: Failed to set cache size");
}
key_datum.dsize = strlen(key_datum.dptr);
time_datum = gdbm_fetch(inst->gdbm, key_datum);
- if (time_datum.dptr != NULL){
+ if (time_datum.dptr != NULL) {
time_t next_reset = 0;
memcpy(&next_reset, time_datum.dptr, sizeof(time_t));
free(time_datum.dptr);
time_datum.dptr = NULL;
- if (next_reset && next_reset <= now){
+ if (next_reset && next_reset <= now) {
inst->last_reset = now;
ret = reset_db(inst);
- if (ret != RLM_MODULE_OK){
+ if (ret != RLM_MODULE_OK) {
ERROR("rlm_counter: reset_db() failed");
return -1;
}
key_datum.dsize = strlen(key_datum.dptr);
time_datum = gdbm_fetch(inst->gdbm, key_datum);
- if (time_datum.dptr != NULL){
+ if (time_datum.dptr != NULL) {
memcpy(&inst->last_reset, time_datum.dptr, sizeof(time_t));
free(time_datum.dptr);
}
- }
- else{
+ } else {
ret = add_defaults(inst);
- if (ret != RLM_MODULE_OK){
+ if (ret != RLM_MODULE_OK) {
ERROR("rlm_counter: add_defaults() failed");
return -1;
}
* Register the counter comparison operation.
* FIXME: move all attributes to DA
*/
- paircompare_register(dict_attrbyvalue(inst->dict_attr, 0), NULL, true, counter_cmp, inst);
+ paircompare_register(inst->dict_attr, NULL, true, counter_cmp, inst);
/*
* Init the mutex
/*
* Write accounting information to this modules database.
*/
-static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
{
rlm_counter_t *inst = instance;
datum key_datum;
if ((key_vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY)) != NULL)
acctstatustype = key_vp->vp_integer;
else {
- DEBUG("rlm_counter: Could not find account status type in packet.");
+ DEBUG("rlm_counter: Could not find account status type in packet");
return RLM_MODULE_NOOP;
}
- if (acctstatustype != PW_STATUS_STOP){
- DEBUG("rlm_counter: We only run on Accounting-Stop packets.");
+ if (acctstatustype != PW_STATUS_STOP) {
+ DEBUG("rlm_counter: We only run on Accounting-Stop packets");
return RLM_MODULE_NOOP;
}
uniqueid_vp = pairfind(request->packet->vps, PW_ACCT_UNIQUE_SESSION_ID, 0, TAG_ANY);
* the counters.
*/
if (inst->reset_time && (inst->reset_time <= request->timestamp)) {
- DEBUG("rlm_counter: Time to reset the database.");
+ DEBUG("rlm_counter: Time to reset the database");
inst->last_reset = inst->reset_time;
find_next_reset(inst,request->timestamp);
pthread_mutex_lock(&inst->mutex);
* Check if we need to watch out for a specific service-type. If yes then check it
*/
if (inst->service_type != NULL) {
- if ((proto_vp = pairfind(request->packet->vps, PW_SERVICE_TYPE, 0, TAG_ANY)) == NULL){
- DEBUG("rlm_counter: Could not find Service-Type attribute in the request. Returning NOOP.");
+ if ((proto_vp = pairfind(request->packet->vps, PW_SERVICE_TYPE, 0, TAG_ANY)) == NULL) {
+ DEBUG("rlm_counter: Could not find Service-Type attribute in the request. Returning NOOP");
return RLM_MODULE_NOOP;
}
- if ((unsigned)proto_vp->vp_integer != inst->service_val){
- DEBUG("rlm_counter: This Service-Type is not allowed. Returning NOOP.");
+ if ((unsigned)proto_vp->vp_integer != inst->service_val) {
+ DEBUG("rlm_counter: This Service-Type is not allowed. Returning NOOP");
return RLM_MODULE_NOOP;
}
}
* If yes reject the packet since it is very old
*/
key_vp = pairfind(request->packet->vps, PW_ACCT_DELAY_TIME, 0, TAG_ANY);
- if (key_vp != NULL){
- if (key_vp->vp_integer != 0 &&
- (request->timestamp - key_vp->vp_integer) < inst->last_reset){
- DEBUG("rlm_counter: This packet is too old. Returning NOOP.");
+ if (key_vp != NULL) {
+ if ((key_vp->vp_integer != 0) && (request->timestamp - (time_t) key_vp->vp_integer) < inst->last_reset) {
+ DEBUG("rlm_counter: This packet is too old. Returning NOOP");
return RLM_MODULE_NOOP;
}
}
* Look for the key. User-Name is special. It means
* The REAL username, after stripping.
*/
- key_vp = (inst->key_attr == PW_USER_NAME) ? request->username : pairfind(request->packet->vps, inst->key_attr, 0, TAG_ANY);
- if (!key_vp){
- DEBUG("rlm_counter: Could not find the key-attribute in the request. Returning NOOP.");
+ key_vp = (inst->key_attr->attr == PW_USER_NAME) ? request->username :
+ pairfind_da(request->packet->vps, inst->key_attr, TAG_ANY);
+ if (!key_vp) {
+ DEBUG("rlm_counter: Could not find the key-attribute in the request. Returning NOOP");
return RLM_MODULE_NOOP;
}
/*
* Look for the attribute to use as a counter.
*/
- count_vp = pairfind(request->packet->vps, inst->count_attr, 0, TAG_ANY);
- if (!count_vp){
- DEBUG("rlm_counter: Could not find the count_attribute in the request.");
+ count_vp = pairfind_da(request->packet->vps, inst->count_attr, TAG_ANY);
+ if (!count_vp) {
+ DEBUG("rlm_counter: Could not find the count_attribute in the request");
return RLM_MODULE_NOOP;
}
DEBUG("rlm_counter: Searching the database for key '%s'",key_vp->vp_strvalue);
pthread_mutex_lock(&inst->mutex);
count_datum = gdbm_fetch(inst->gdbm, key_datum);
- pthread_mutex_unlock(&inst->mutex);
- if (!count_datum.dptr){
- DEBUG("rlm_counter: Could not find the requested key in the database.");
+ if (!count_datum.dptr) {
+ DEBUG("rlm_counter: Could not find the requested key in the database");
counter.user_counter = 0;
if (uniqueid_vp != NULL)
- strlcpy(counter.uniqueid,uniqueid_vp->vp_strvalue,
- sizeof(counter.uniqueid));
+ strlcpy(counter.uniqueid,uniqueid_vp->vp_strvalue, sizeof(counter.uniqueid));
else
memset((char *)counter.uniqueid,0,UNIQUEID_MAX_LEN);
- }
- else{
- DEBUG("rlm_counter: Key found.");
+ } else {
+ DEBUG("rlm_counter: Key found");
memcpy(&counter, count_datum.dptr, sizeof(rad_counter));
free(count_datum.dptr);
DEBUG("rlm_counter: Counter Unique ID = '%s'",counter.uniqueid);
- if (uniqueid_vp != NULL){
- if (strncmp(uniqueid_vp->vp_strvalue,counter.uniqueid, UNIQUEID_MAX_LEN - 1) == 0){
- DEBUG("rlm_counter: Unique IDs for user match. Droping the request.");
+ if (uniqueid_vp != NULL) {
+ if (strncmp(uniqueid_vp->vp_strvalue,counter.uniqueid, UNIQUEID_MAX_LEN - 1) == 0) {
+ DEBUG("rlm_counter: Unique IDs for user match. Droping the request");
+ pthread_mutex_unlock(&inst->mutex);
return RLM_MODULE_NOOP;
}
- strlcpy(counter.uniqueid,uniqueid_vp->vp_strvalue,
- sizeof(counter.uniqueid));
+ strlcpy(counter.uniqueid,uniqueid_vp->vp_strvalue, sizeof(counter.uniqueid));
}
DEBUG("rlm_counter: User=%s, Counter=%d.",request->username->vp_strvalue,counter.user_counter);
}
- if (inst->count_attr == PW_ACCT_SESSION_TIME) {
+ if (inst->count_attr->attr == PW_ACCT_SESSION_TIME) {
/*
* If session time < diff then the user got in after the
* last reset. So add his session time, otherwise add the
* day). That is the right thing
*/
diff = request->timestamp - inst->last_reset;
- counter.user_counter += (count_vp->vp_integer < diff) ? count_vp->vp_integer : diff;
+ counter.user_counter += ((time_t) count_vp->vp_integer < diff) ? count_vp->vp_integer : diff;
} else if (count_vp->da->type == PW_TYPE_INTEGER) {
/*
count_datum.dptr = (char *) &counter;
count_datum.dsize = sizeof(rad_counter);
- DEBUG("rlm_counter: Storing new value in database.");
- pthread_mutex_lock(&inst->mutex);
+ DEBUG("rlm_counter: Storing new value in database");
ret = gdbm_store(inst->gdbm, key_datum, count_datum, GDBM_REPLACE);
pthread_mutex_unlock(&inst->mutex);
if (ret < 0) {
- ERROR("rlm_counter: Failed storing data to %s: %s",
- inst->filename, gdbm_strerror(gdbm_errno));
+ ERROR("rlm_counter: Failed storing data to %s: %s", inst->filename, gdbm_strerror(gdbm_errno));
return RLM_MODULE_FAIL;
}
- DEBUG("rlm_counter: New value stored successfully.");
+ DEBUG("rlm_counter: New value stored successfully");
return RLM_MODULE_OK;
}
* from the database. The authentication code only needs to check
* the password, the rest is done here.
*/
-static rlm_rcode_t mod_authorize(UNUSED void *instance, UNUSED REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, UNUSED REQUEST *request)
{
rlm_counter_t *inst = instance;
rlm_rcode_t rcode = RLM_MODULE_NOOP;
datum key_datum;
datum count_datum;
rad_counter counter;
- unsigned int res = 0;
VALUE_PAIR *key_vp, *check_vp;
VALUE_PAIR *reply_item;
char msg[128];
pthread_mutex_lock(&inst->mutex);
rcode2 = reset_db(inst);
pthread_mutex_unlock(&inst->mutex);
- if (rcode2 != RLM_MODULE_OK)
+ if (rcode2 != RLM_MODULE_OK) {
return rcode2;
+ }
}
* The REAL username, after stripping.
*/
DEBUG2("rlm_counter: Entering module authorize code");
- key_vp = (inst->key_attr == PW_USER_NAME) ? request->username : pairfind(request->packet->vps, inst->key_attr, 0, TAG_ANY);
+ key_vp = (inst->key_attr->attr == PW_USER_NAME) ? request->username :
+ pairfind_da(request->packet->vps, inst->key_attr, TAG_ANY);
if (!key_vp) {
DEBUG2("rlm_counter: Could not find Key value pair");
return rcode;
/*
* Look for the check item
*/
- if ((check_vp= pairfind(request->config_items, inst->check_attr, 0, TAG_ANY)) == NULL) {
+ if ((check_vp = pairfind_da(request->config_items, inst->check_attr, TAG_ANY)) == NULL) {
DEBUG2("rlm_counter: Could not find Check item value pair");
return rcode;
}
pthread_mutex_lock(&inst->mutex);
count_datum = gdbm_fetch(inst->gdbm, key_datum);
pthread_mutex_unlock(&inst->mutex);
- if (count_datum.dptr != NULL){
- DEBUG("rlm_counter: Key Found.");
+ if (count_datum.dptr != NULL) {
+ DEBUG("rlm_counter: Key Found");
memcpy(&counter, count_datum.dptr, sizeof(rad_counter));
free(count_datum.dptr);
}
else
- DEBUG("rlm_counter: Could not find the requested key in the database.");
+ DEBUG("rlm_counter: Could not find the requested key in the database");
/*
* Check if check item > counter
*/
DEBUG("rlm_counter: Check item = %d, Count = %d",check_vp->vp_integer,counter.user_counter);
- res=check_vp->vp_integer - counter.user_counter;
- if (res > 0) {
+ if (check_vp->vp_integer > counter.user_counter) {
+ unsigned int res;
+
+ res = check_vp->vp_integer - counter.user_counter;
+
DEBUG("rlm_counter: res is greater than zero");
- if (inst->count_attr == PW_ACCT_SESSION_TIME) {
+ if (inst->count_attr->attr == PW_ACCT_SESSION_TIME) {
/*
* Do the following only if the count attribute is
* AcctSessionTime
*/
/*
- * We are assuming that simultaneous-use=1. But
- * even if that does not happen then our user
- * could login at max for 2*max-usage-time Is
- * that acceptable?
- */
+ * We are assuming that simultaneous-use=1. But
+ * even if that does not happen then our user
+ * could login at max for 2*max-usage-time Is
+ * that acceptable?
+ */
/*
- * User is allowed, but set Session-Timeout.
- * Stolen from main/auth.c
- */
+ * User is allowed, but set Session-Timeout.
+ * Stolen from main/auth.c
+ */
/*
- * If we are near a reset then add the next
- * limit, so that the user will not need to
- * login again
+ * If we are near a reset then add the next
+ * limit, so that the user will not need to
+ * login again
* Before that set the return value to the time
* remaining to next reset
- */
- if (inst->reset_time && (
- res >= (inst->reset_time - request->timestamp))) {
+ */
+ if (inst->reset_time && (res >= (inst->reset_time - request->timestamp))) {
res = inst->reset_time - request->timestamp;
res += check_vp->vp_integer;
}
reply_item = pairfind(request->reply->vps, PW_SESSION_TIMEOUT, 0, TAG_ANY);
- if (reply_item && (reply_item->vp_integer > res)) {
- reply_item->vp_integer = res;
+ if (reply_item) {
+ if (reply_item->vp_integer > res) {
+ reply_item->vp_integer = res;
+ }
} else {
- reply_item = radius_paircreate(request, &request->reply->vps, PW_SESSION_TIMEOUT, 0);
+ reply_item = radius_paircreate(request->reply, &request->reply->vps, PW_SESSION_TIMEOUT, 0);
reply_item->vp_integer = res;
}
- }
- else if (inst->reply_attr) {
- reply_item = pairfind(request->reply->vps, inst->reply_attr, 0, TAG_ANY);
- if (reply_item && (reply_item->vp_integer > res)) {
- reply_item->vp_integer = res;
+ } else if (inst->reply_attr) {
+ reply_item = pairfind_da(request->reply->vps, inst->reply_attr, TAG_ANY);
+ if (reply_item) {
+ if (reply_item->vp_integer > res) {
+ reply_item->vp_integer = res;
+ }
} else {
- reply_item = radius_paircreate(request, &request->reply->vps, inst->reply_attr, 0);
+ reply_item = radius_paircreate(request->reply, &request->reply->vps, inst->reply_attr->attr,
+ inst->reply_attr->vendor);
reply_item->vp_integer = res;
}
}
DEBUG2("rlm_counter: (Check item - counter) is greater than zero");
DEBUG2("rlm_counter: Authorized user %s, check_item=%d, counter=%d",
key_vp->vp_strvalue,check_vp->vp_integer,counter.user_counter);
- DEBUG2("rlm_counter: Sent Reply-Item for user %s, Type=Session-Timeout, value=%d",
- key_vp->vp_strvalue,res);
+ DEBUG2("rlm_counter: Sent Reply-Item for user %s, Type=Session-Timeout, value=%d", key_vp->vp_strvalue,res);
} else {
/*
* User is denied access, send back a reply message
*/
- sprintf(msg, "Your maximum %s usage time has been reached",
- inst->reset);
+ sprintf(msg, "Your maximum %s usage time has been reached", inst->reset);
pairmake_reply("Reply-Message", msg, T_OP_EQ);
- REDEBUG("Maximum %s usage time reached",
- inst->reset);
+ REDEBUG("Maximum %s usage time reached", inst->reset);
rcode = RLM_MODULE_REJECT;
DEBUG2("rlm_counter: Rejected user %s, check_item=%d, counter=%d",
mod_detach, /* detach */
{
NULL, /* authentication */
- mod_authorize, /* authorization */
+ mod_authorize, /* authorization */
NULL, /* preaccounting */
- mod_accounting, /* accounting */
+ mod_accounting, /* accounting */
NULL, /* checksimul */
NULL, /* pre-proxy */
NULL, /* post-proxy */
KRB5 - (reserved) Kerberos V5 authentication
NTLM - Microsoft NTLM v1 authentication. SHOULD be implemented as
- MS-CHAP v1 (RFC2433/RFC2458)
+ MS-CHAP v1 (RFC2433/RFC2458)
NTLM2 - (reserved) Microsoft NTLM v2 authentication. SHOULD be
- implemented as MS-CHAP v2 (RFC2759/RFC2458)
+ implemented as MS-CHAP v2 (RFC2759/RFC2458)
CRAM-MD4 - MD4 digest authentication
}
-static rlm_rcode_t mod_authenticate(UNUSED void * instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(UNUSED void * instance, REQUEST *request)
{
VALUE_PAIR *authtype, *challenge, *response, *password;
uint8_t buffer[64];
password = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
if(!password) {
- AUTH("rlm_cram: Cleartext-Password is required for authentication.");
+ AUTH("rlm_cram: Cleartext-Password is required for authentication");
return RLM_MODULE_INVALID;
}
authtype = pairfind(request->packet->vps, SM_AUTHTYPE, VENDORPEC_SM, TAG_ANY);
#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/modules.h>
+#include <ctype.h>
#include <time.h>
typedef struct rlm_date_t {
} rlm_date_t;
static const CONF_PARSER module_config[] = {
- {"format", PW_TYPE_STRING_PTR, offsetof(rlm_date_t, fmt), NULL, "%b %e %Y %H:%M:%S %Z"},
+ { "format", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_date_t, fmt), "%b %e %Y %H:%M:%S %Z" },
{NULL, -1, 0, NULL, NULL}
};
module_t rlm_date = {
RLM_MODULE_INIT,
"date", /* Name */
- RLM_TYPE_CHECK_CONFIG_SAFE, /* type */
+ 0, /* type */
sizeof(rlm_date_t),
module_config,
mod_instantiate, /* instantiation */
*/
typedef struct detail_instance {
char const *name; //!< Instance name.
- char *filename; //!< File/path to write to.
- int perm; //!< Permissions to use for new files.
- char *group; //!< Group to use for new files.
+ char const *filename; //!< File/path to write to.
+ uint32_t perm; //!< Permissions to use for new files.
+ char const *group; //!< Group to use for new files.
- int dirperm; //!< Directory permissions to use for new files.
-
- char *header; //!< Header format.
+ char const *header; //!< Header format.
bool locking; //!< Whether the file should be locked.
bool log_srcdst; //!< Add IP src/dst attributes to entries.
+ fr_logfile_t *lf; //!< Log file handler
+
fr_hash_table_t *ht; //!< Holds suppressed attributes.
} detail_instance_t;
static const CONF_PARSER module_config[] = {
- { "detailfile", PW_TYPE_FILE_OUTPUT | PW_TYPE_DEPRECATED, offsetof(detail_instance_t, filename),
- NULL, NULL },
- { "filename", PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED, offsetof(detail_instance_t, filename),
- NULL, "%A/%{Client-IP-Address}/detail" },
- { "header", PW_TYPE_STRING_PTR, offsetof(detail_instance_t, header), NULL, "%t" },
- { "detailperm", PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, offsetof(detail_instance_t, perm), NULL, NULL },
- { "permissions", PW_TYPE_INTEGER, offsetof(detail_instance_t, perm), NULL, "0600" },
- { "group", PW_TYPE_STRING_PTR, offsetof(detail_instance_t, group), NULL, NULL},
- { "dir_permissions", PW_TYPE_INTEGER, offsetof(detail_instance_t, dirperm), NULL, "0755" },
- { "locking", PW_TYPE_BOOLEAN, offsetof(detail_instance_t, locking), NULL, "no" },
- { "log_packet_header", PW_TYPE_BOOLEAN, offsetof(detail_instance_t, log_srcdst), NULL, "no" },
+ { "detailfile", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_DEPRECATED, detail_instance_t, filename), NULL },
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED, detail_instance_t, filename), "%A/%{Client-IP-Address}/detail" },
+ { "header", FR_CONF_OFFSET(PW_TYPE_STRING, detail_instance_t, header), "%t" },
+ { "detailperm", FR_CONF_OFFSET(PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, detail_instance_t, perm), NULL },
+ { "permissions", FR_CONF_OFFSET(PW_TYPE_INTEGER, detail_instance_t, perm), "0600" },
+ { "group", FR_CONF_OFFSET(PW_TYPE_STRING, detail_instance_t, group), NULL },
+ { "locking", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, detail_instance_t, locking), "no" },
+ { "log_packet_header", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, detail_instance_t, log_srcdst), "no" },
{ NULL, -1, 0, NULL, NULL }
};
inst->name = cf_section_name1(conf);
}
+ inst->lf= fr_logfile_init(inst);
+ if (!inst->lf) {
+ cf_log_err_cs(conf, "Failed creating log file context");
+ return -1;
+ }
+
/*
* Suppress certain attributes.
*/
return 0;
}
+/*
+ * Wrapper for VPs allocated on the stack.
+ */
+static void detail_vp_print(TALLOC_CTX *ctx, FILE *out, VALUE_PAIR const *stacked)
+{
+ VALUE_PAIR *vp;
+
+ vp = talloc(ctx, VALUE_PAIR);
+ if (!vp) return;
+
+ memcpy(vp, stacked, sizeof(*vp));
+ vp_print(out, vp);
+ talloc_free(vp);
+}
+
+
/** Write a single detail entry to file pointer
*
* @param[in] out Where to write entry.
#define WRITE(fmt, ...) do {\
if (fprintf(out, fmt, ## __VA_ARGS__) < 0) {\
- RERROR("Failed writing to detail file: %s", strerror(errno));\
+ RERROR("Failed writing to detail file: %s", fr_syserror(errno));\
return -1;\
}\
} while(0)
* Print out names, if they're OK.
* Numbers, if not.
*/
- if ((packet->code > 0) && (packet->code < FR_MAX_PACKET_CODE)) {
+ if (is_radius_code(packet->code)) {
WRITE("\tPacket-Type = %s\n", fr_packet_codes[packet->code]);
} else {
WRITE("\tPacket-Type = %d\n", packet->code);
break;
}
- vp_print(out, &src_vp);
- vp_print(out, &dst_vp);
+ detail_vp_print(request, out, &src_vp);
+ detail_vp_print(request, out, &dst_vp);
src_vp.da = dict_attrbyvalue(PW_PACKET_SRC_PORT, 0);
src_vp.vp_integer = packet->src_port;
dst_vp.da = dict_attrbyvalue(PW_PACKET_DST_PORT, 0);
dst_vp.vp_integer = packet->dst_port;
- vp_print(out, &src_vp);
- vp_print(out, &dst_vp);
+ detail_vp_print(request, out, &src_vp);
+ detail_vp_print(request, out, &dst_vp);
}
{
vp_cursor_t cursor;
/* Write each attribute/value to the log file */
- for (vp = paircursor(&cursor, &packet->vps);
+ for (vp = fr_cursor_init(&cursor, &packet->vps);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
if (inst->ht &&
fr_hash_table_finddata(inst->ht, vp->da)) continue;
/*
* Do detail, compatible with old accounting
*/
-static rlm_rcode_t detail_do(void *instance, REQUEST *request, RADIUS_PACKET *packet, bool compat)
+static rlm_rcode_t CC_HINT(nonnull) detail_do(void *instance, REQUEST *request, RADIUS_PACKET *packet, bool compat)
{
int outfd;
char buffer[DIRLEN];
- char *p;
- struct stat st;
- int locked;
- int lock_count;
- struct timeval tv;
- off_t fsize;
FILE *outfp;
#ifdef HAVE_GRP_H
detail_instance_t *inst = instance;
- rad_assert(request != NULL);
-
- /*
- * Nothing to log: don't do anything.
- */
- if (!packet) {
- return RLM_MODULE_NOOP;
- }
-
/*
* Generate the path for the detail file. Use the same
* format, but truncate at the last /. Then feed it
#endif
#endif
- /*
- * Grab the last directory delimiter.
- */
- p = strrchr(buffer,'/');
-
- /*
- * There WAS a directory delimiter there, and the file
- * doesn't exist, so we must create it the directories..
- */
- if (p) {
- *p = '\0';
-
- /*
- * Always try to create the directory. If it
- * exists, rad_mkdir() will check via stat(), and
- * return immediately.
- *
- * This catches the case where some idiot deleted
- * a directory that the server was using.
- */
- if (rad_mkdir(buffer, inst->dirperm) < 0) {
- RERROR("Failed to create directory %s: %s", buffer, strerror(errno));
- return RLM_MODULE_FAIL;
- }
-
- *p = '/';
- } /* else there was no directory delimiter. */
-
- locked = 0;
- lock_count = 0;
- do {
- /*
- * Open & create the file, with the given
- * permissions.
- */
- if ((outfd = open(buffer, O_WRONLY | O_APPEND | O_CREAT, inst->perm)) < 0) {
- RERROR("Couldn't open file %s: %s", buffer, strerror(errno));
- return RLM_MODULE_FAIL;
- }
-
- /*
- * If we fail to aquire the filelock in 80 tries
- * (approximately two seconds) we bail out.
- */
- if (inst->locking) {
- lseek(outfd, 0L, SEEK_SET);
- if (rad_lockfd_nonblock(outfd, 0) < 0) {
- close(outfd);
- tv.tv_sec = 0;
- tv.tv_usec = 25000;
- select(0, NULL, NULL, NULL, &tv);
- lock_count++;
- continue;
- }
-
- /*
- * The file might have been deleted by
- * radrelay while we tried to acquire
- * the lock (race condition)
- */
- if (fstat(outfd, &st) != 0) {
- RERROR("Couldn't stat file %s: %s", buffer, strerror(errno));
- close(outfd);
- return RLM_MODULE_FAIL;
- }
- if (st.st_nlink == 0) {
- RDEBUG2("File '%s' removed by another program, retrying", buffer);
- close(outfd);
- lock_count = 0;
- continue;
- }
-
- RDEBUG2("Acquired filelock, tried %d time(s)", lock_count + 1);
- locked = 1;
- }
- } while (inst->locking && !locked && lock_count < 80);
-
- if (inst->locking && !locked) {
- close(outfd);
- RERROR("Failed to acquire filelock for '%s', giving up", buffer);
+ outfd = fr_logfile_open(inst->lf, buffer, inst->perm);
+ if (outfd < 0) {
+ RERROR("Couldn't open file %s: %s", buffer, fr_strerror());
return RLM_MODULE_FAIL;
}
-
#ifdef HAVE_GRP_H
if (inst->group != NULL) {
gid = strtol(inst->group, &endptr, 10);
skip_group:
#endif
- fsize = lseek(outfd, 0L, SEEK_END);
- if (fsize < 0) {
- RERROR("Failed to seek to the end of detail file '%s'", buffer);
- close(outfd);
- return RLM_MODULE_FAIL;
- }
-
/*
* Open the output fp for buffering.
*/
if ((outfp = fdopen(outfd, "a")) == NULL) {
- RERROR("Couldn't open file %s: %s", buffer, strerror(errno));
- close(outfd);
+ RERROR("Couldn't open file %s: %s", buffer, fr_syserror(errno));
+ fail:
+ if (outfp) fclose(outfp);
+ fr_logfile_unlock(inst->lf, outfd);
return RLM_MODULE_FAIL;
}
- if (detail_write(outfp, inst, request, packet, compat) < 0) {
- fclose(outfp);
- return RLM_MODULE_FAIL;
- }
+ if (detail_write(outfp, inst, request, packet, compat) < 0) goto fail;
/*
- * If we can't flush it to disk, truncate the file and return an error.
+ * Flush everything
*/
- if (fflush(outfp) != 0) {
- int ret;
- ret = ftruncate(outfd, fsize);
- if (ret) {
- REDEBUG4("Failed truncating detail file: %s", strerror(ret));
- }
-
- fclose(outfp);
- return RLM_MODULE_FAIL;
- }
-
fclose(outfp);
+ fr_logfile_unlock(inst->lf, outfd); /* do NOT close outfp */
/*
* And everything is fine.
/*
* Accounting - write the detail files.
*/
-static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
{
#ifdef WITH_DETAIL
if (request->listener->type == RAD_LISTEN_DETAIL &&
strcmp(((detail_instance_t *)instance)->filename,
((listen_detail_t *)request->listener->data)->filename) == 0) {
- RDEBUG("Suppressing writes to detail file as the request was just read from a detail file.");
+ RDEBUG("Suppressing writes to detail file as the request was just read from a detail file");
return RLM_MODULE_NOOP;
}
#endif
/*
* Incoming Access Request - write the detail files.
*/
-static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
{
return detail_do(instance, request, request->packet, false);
}
/*
* Outgoing Access-Request Reply - write the detail files.
*/
-static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
{
return detail_do(instance, request, request->reply, false);
}
/*
* Incoming CoA - write the detail files.
*/
-static rlm_rcode_t mod_recv_coa(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_recv_coa(void *instance, REQUEST *request)
{
return detail_do(instance, request, request->packet, false);
}
/*
* Outgoing CoA - write the detail files.
*/
-static rlm_rcode_t mod_send_coa(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_send_coa(void *instance, REQUEST *request)
{
return detail_do(instance, request, request->reply, false);
}
* Outgoing Access-Request to home server - write the detail files.
*/
#ifdef WITH_PROXY
-static rlm_rcode_t mod_pre_proxy(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_pre_proxy(void *instance, REQUEST *request)
{
if (request->proxy && request->proxy->vps) {
return detail_do(instance, request, request->proxy, false);
/*
* Outgoing Access-Request Reply - write the detail files.
*/
-static rlm_rcode_t mod_post_proxy(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_post_proxy(void *instance, REQUEST *request)
{
if (request->proxy_reply && request->proxy_reply->vps) {
return detail_do(instance, request, request->proxy_reply, false);
rcode = mod_accounting(instance, request);
if (rcode == RLM_MODULE_OK) {
- request->reply->code = PW_ACCOUNTING_RESPONSE;
+ request->reply->code = PW_CODE_ACCOUNTING_RESPONSE;
}
return rcode;
}
module_t rlm_detail = {
RLM_MODULE_INIT,
"detail",
- RLM_TYPE_THREAD_UNSAFE | RLM_TYPE_CHECK_CONFIG_SAFE | RLM_TYPE_HUP_SAFE,
+ RLM_TYPE_HUP_SAFE,
sizeof(detail_instance_t),
module_config,
mod_instantiate, /* instantiation */
return RLM_MODULE_NOOP;
}
- paircursor(&cursor, &first);
- while ((i = pairfindnext(&cursor, PW_DIGEST_ATTRIBUTES, 0, TAG_ANY))) {
+ fr_cursor_init(&cursor, &first);
+ while ((i = fr_cursor_next_by_num(&cursor, PW_DIGEST_ATTRIBUTES, 0, TAG_ANY))) {
int length = i->length;
int attrlen;
uint8_t const *p = i->vp_octets;
/*
* Convert them to something sane.
*/
- RDEBUG("Digest-Attributes look OK. Converting them to something more useful.");
- pairfirst(&cursor);
- while ((i = pairfindnext(&cursor, PW_DIGEST_ATTRIBUTES, 0, TAG_ANY))) {
+ RDEBUG("Digest-Attributes look OK. Converting them to something more useful");
+ fr_cursor_first(&cursor);
+ while ((i = fr_cursor_next_by_num(&cursor, PW_DIGEST_ATTRIBUTES, 0, TAG_ANY))) {
int length = i->length;
int attrlen;
uint8_t const *p = &i->vp_octets[0];
*
* Didn't they know that VSA's exist?
*/
- sub = radius_paircreate(request, &request->packet->vps,
+ sub = radius_paircreate(request->packet, &request->packet->vps,
PW_DIGEST_REALM - 1 + p[0], 0);
sub->length = attrlen - 2;
sub->vp_strvalue = q = talloc_array(sub, char, sub->length + 1);
return RLM_MODULE_OK;
}
-static rlm_rcode_t mod_authorize(UNUSED void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, REQUEST *request)
{
rlm_rcode_t rcode;
/*
* Perform all of the wondrous variants of digest authentication.
*/
-static rlm_rcode_t mod_authenticate(UNUSED void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(UNUSED void *instance, REQUEST *request)
{
int i;
size_t a1_len, a2_len, kd_len;
passwd = pairfind(request->config_items, PW_DIGEST_HA1, 0, TAG_ANY);
if (passwd) {
if (passwd->length != 32) {
- RAUTH("Digest-HA1 has invalid length, authentication failed.");
+ RAUTH("Digest-HA1 has invalid length, authentication failed");
return RLM_MODULE_INVALID;
}
} else {
passwd = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
}
if (!passwd) {
- RAUTH("Cleartext-Password or Digest-HA1 is required for authentication.");
+ RAUTH("Cleartext-Password or Digest-HA1 is required for authentication");
return RLM_MODULE_INVALID;
}
module_t rlm_digest = {
RLM_MODULE_INIT,
"digest",
- RLM_TYPE_CHECK_CONFIG_SAFE, /* type */
+ 0, /* type */
0,
NULL, /* CONF_PARSER */
NULL, /* instantiation */
/*
* Find the client definition.
*/
-static rlm_rcode_t mod_authorize(UNUSED void *instance,
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance,
REQUEST *request)
{
size_t length;
value = cf_pair_value(cp);
if (!value) {
- RDEBUG("No value given for the directory entry in the client.");
+ RDEBUG("No value given for the directory entry in the client");
return RLM_MODULE_NOOP;
}
return RLM_MODULE_OK;
}
#else
-static rlm_rcode_t mod_authorize(UNUSED void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, REQUEST *request)
{
- RDEBUG("Dynamic clients are unsupported in this build.");
+ RDEBUG("Dynamic clients are unsupported in this build");
return RLM_MODULE_FAIL;
}
#endif
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
ac_sub_configure=$ac_srcdir/configure.gnu
elif test -f "$ac_srcdir/configure"; then
ac_sub_configure=$ac_srcdir/configure
- elif test -f "$ac_srcdir/configure.ac"; then
+ elif test -f "$ac_srcdir/configure.in"; then
# This should be Cygnus configure.
ac_sub_configure=$ac_aux_dir/configure
else
* debugging. This removes the symbols needed by
* valgrind.
*/
- if (!mainconfig.debug_memory)
+ if (!main_config.debug_memory)
#endif
if (inst->handle) dlclose(inst->handle);
/*
* The name of the module were trying to load
*/
- mod_name = talloc_asprintf(method, "rlm_eap_%s", method->name);
+ mod_name = talloc_typed_asprintf(method, "rlm_eap_%s", method->name);
/*
* dlopen is case sensitive
*/
static eap_type_t eap_process_nak(rlm_eap_t *inst, REQUEST *request,
eap_type_t type,
- eap_type_data_t *nak)
+ eap_type_data_t *nak)
{
unsigned int i;
VALUE_PAIR *vp;
* Multiple levels of nesting are invalid.
*/
if (handler->request->parent && handler->request->parent->parent) {
- RDEBUG2("Multiple levels of TLS nesting is invalid.");
+ RDEBUG2("Multiple levels of TLS nesting is invalid");
return EAP_INVALID;
}
handler) == 0) {
REDEBUG2("Failed continuing EAP %s (%d) session. "
"EAP sub-module failed",
- eap_type2name(type->num),
+ eap_type2name(type->num),
type->num);
return EAP_INVALID;
*/
case PW_EAP_SUCCESS:
case PW_EAP_FAILURE:
- break;
+ break;
/*
* We've sent a response to their
* request, the Id is incremented.
*/
default:
- ++reply->id;
+ ++reply->id;
}
} else {
RDEBUG2("Underlying EAP-Type set EAP ID to %d",
}
eap_packet = (eap_packet_raw_t *)reply->packet;
- vp = radius_paircreate(request, &request->reply->vps, PW_EAP_MESSAGE, 0);
+ vp = radius_paircreate(request->reply, &request->reply->vps, PW_EAP_MESSAGE, 0);
if (!vp) return RLM_MODULE_INVALID;
vp->length = eap_packet->length[0] * 256 + eap_packet->length[1];
rcode = RLM_MODULE_OK;
if (!request->reply->code) switch(reply->code) {
case PW_EAP_RESPONSE:
- request->reply->code = PW_AUTHENTICATION_ACK;
+ request->reply->code = PW_CODE_AUTHENTICATION_ACK;
rcode = RLM_MODULE_HANDLED; /* leap weirdness */
break;
case PW_EAP_SUCCESS:
- request->reply->code = PW_AUTHENTICATION_ACK;
+ request->reply->code = PW_CODE_AUTHENTICATION_ACK;
rcode = RLM_MODULE_OK;
break;
case PW_EAP_FAILURE:
- request->reply->code = PW_AUTHENTICATION_REJECT;
+ request->reply->code = PW_CODE_AUTHENTICATION_REJECT;
rcode = RLM_MODULE_REJECT;
break;
case PW_EAP_REQUEST:
- request->reply->code = PW_ACCESS_CHALLENGE;
+ request->reply->code = PW_CODE_ACCESS_CHALLENGE;
rcode = RLM_MODULE_HANDLED;
break;
default:
* we do so WITHOUT setting a reply code, as the
* request is being proxied.
*/
- if (request->options & RAD_REQUEST_OPTION_PROXY_EAP) {
+ if (request->log.lvl & RAD_REQUEST_OPTION_PROXY_EAP) {
return RLM_MODULE_HANDLED;
}
/* Should never enter here */
ERROR("rlm_eap: reply code %d is unknown, Rejecting the request.", reply->code);
- request->reply->code = PW_AUTHENTICATION_REJECT;
+ request->reply->code = PW_CODE_AUTHENTICATION_REJECT;
reply->code = PW_EAP_FAILURE;
rcode = RLM_MODULE_REJECT;
break;
*/
vp = pairfind(request->packet->vps, PW_EAP_TYPE, 0, TAG_ANY);
if (vp && vp->vp_integer == 0) {
- RDEBUG2("Found EAP-Message, but EAP-Type = None, so we're not doing EAP.");
+ RDEBUG2("Found EAP-Message, but EAP-Type = None, so we're not doing EAP");
return EAP_NOOP;
}
if (eap_msg->length < (EAP_HEADER_LEN + 1)) {
if (proxy) goto do_proxy;
- RDEBUG2("Ignoring EAP-Message which is too short to be meaningful.");
+ RDEBUG2("Ignoring EAP-Message which is too short to be meaningful");
return EAP_FAIL;
}
(eap_msg->vp_octets[0] >= PW_EAP_MAX_CODES)) {
RDEBUG2("Unknown EAP packet");
} else {
- RDEBUG2("EAP packet type %s id %d length %d",
+ RDEBUG2("EAP packet type %s id %d length %zu",
eap_codes[eap_msg->vp_octets[0]],
eap_msg->vp_octets[1],
eap_msg->length);
*/
if ((eap_msg->vp_octets[0] != PW_EAP_REQUEST) &&
(eap_msg->vp_octets[0] != PW_EAP_RESPONSE)) {
- RDEBUG2("Ignoring EAP packet which we don't know how to handle.");
+ RDEBUG2("Ignoring EAP packet which we don't know how to handle");
return EAP_FAIL;
}
((eap_msg->vp_octets[4] == 0) ||
(eap_msg->vp_octets[4] >= PW_EAP_MAX_TYPES) ||
(!inst->methods[eap_msg->vp_octets[4]]))) {
- RDEBUG2(" Ignoring Unknown EAP type");
+ RDEBUG2("Ignoring Unknown EAP type");
return EAP_NOOP;
}
if ((eap_msg->vp_octets[4] == PW_EAP_TTLS) ||
(eap_msg->vp_octets[4] == PW_EAP_PEAP)) {
- RDEBUG2("Continuing tunnel setup.");
+ RDEBUG2("Continuing tunnel setup");
return EAP_OK;
}
/*
- * We return ok in response to EAP identity and MSCHAP success/fail
+ * We return ok in response to EAP identity
* This means we can write:
*
* eap {
RDEBUG2("EAP-Identity reply, returning 'ok' so we can short-circuit the rest of authorize");
return EAP_OK;
}
- if ((eap_msg->vp_octets[4] == PW_EAP_MSCHAPV2) && (eap_msg->length >= 6)) {
- switch (eap_msg->vp_octets[5]) {
- case 3:
- RDEBUG2("EAP-MSCHAPV2 success, returning short-circuit ok");
- return EAP_OK;
- case 4:
- RDEBUG2("EAP-MSCHAPV2 failure, returning short-circuit ok");
- return EAP_OK;
- }
- }
/*
* Later EAP messages are longer than the 'start'
* High level EAP packet checks
*/
if ((len <= EAP_HEADER_LEN) ||
- ((eap_packet->code != PW_EAP_RESPONSE) &&
- (eap_packet->code != PW_EAP_REQUEST)) ||
+ ((eap_packet->code != PW_EAP_RESPONSE) &&
+ (eap_packet->code != PW_EAP_REQUEST)) ||
(eap_packet->data[0] <= 0) ||
(eap_packet->data[0] >= PW_EAP_MAX_TYPES)) {
*/
if (strncmp(handler->identity, vp->vp_strvalue,
MAX_STRING_LEN) != 0) {
- RDEBUG("Identity does not match User-Name. Authentication failed.");
+ RDEBUG("Identity does not match User-Name. Authentication failed");
goto error;
}
}
*/
if (strncmp(handler->identity, vp->vp_strvalue,
MAX_STRING_LEN) != 0) {
- RDEBUG("Identity does not match User-Name, setting from EAP Identity.");
+ RDEBUG("Identity does not match User-Name, setting from EAP Identity");
goto error2;
}
}
for (i = 0; i < 12; i += 2) {
kc[i>>1] = (x[i + 18] << 6) |
- (x[i + 19] << 2) |
- (x[i + 20] >> 2);
+ (x[i + 19] << 2) |
+ (x[i + 20] >> 2);
}
kc[6] = (x[30] << 6) | (x[31] << 2);
int chbind_process(REQUEST *req, CHBIND_REQ *chbind_req)
{
- int rcode = PW_AUTHENTICATION_REJECT;
+ int rcode = PW_CODE_AUTHENTICATION_REJECT;
REQUEST *fake = NULL;
VALUE_PAIR *vp = NULL;
uint8_t *attr_data;
(chbind_req != NULL) &&
(chbind_req->chbind_req_pkt != NULL));
if (chbind_req->chbind_req_len < 4)
- return PW_AUTHENTICATION_REJECT; /* Is this the right response? */
+ return PW_CODE_AUTHENTICATION_REJECT; /* Is this the right response? */
/* Set-up NULL response for cases where channel bindings can't be processed */
chbind_req->chbind_resp = NULL;
/* If radaddr2vp fails, return NULL string for
channel binding response */
request_free(&fake);
- return PW_AUTHENTICATION_ACK;
+ return PW_CODE_AUTHENTICATION_ACK;
}
/* TODO: need to account for the possibility of rad_attr2vp generating
multiple vps */
fprintf(fr_log_fp, "server %s {\n",
(fake->server == NULL) ? "" : fake->server);
}
- rcode = rad_authenticate(fake);
+ rcode = rad_virtual_server(fake);
switch(rcode) {
/* If rad_authenticate succeeded, build a reply */
case RLM_MODULE_OK:
case RLM_MODULE_HANDLED:
if ((chbind_req->chbind_resp = chbind_build_response(fake, &chbind_req->chbind_resp_len)) != NULL)
- rcode = PW_AUTHENTICATION_ACK;
+ rcode = PW_CODE_AUTHENTICATION_ACK;
else
- rcode = PW_AUTHENTICATION_REJECT;
+ rcode = PW_CODE_AUTHENTICATION_REJECT;
break;
/* If we got any other response from rad_authenticate, it maps to a reject */
default:
- rcode = PW_AUTHENTICATION_REJECT;
+ rcode = PW_CODE_AUTHENTICATION_REJECT;
break;
}
#define ATTRIBUTE_EAP_SIM_KC2 1213
#define ATTRIBUTE_EAP_SIM_KC3 1214
+#define ATTRIBUTE_EAP_SIM_KI 1215
+#define ATTRIBUTE_EAP_SIM_ALGO_VERSION 1216
+
enum eapsim_subtype {
eapsim_start = 10,
eapsim_challenge = 11,
eapsim_server_maxstates
};
-#define PW_EAP_SIM_RAND 1
-#define PW_EAP_SIM_PADDING 6
-#define PW_EAP_SIM_NONCE_MT 7
-#define PW_EAP_SIM_PERMANENT_ID_REQ 10
-#define PW_EAP_SIM_MAC 11
-#define PW_EAP_SIM_NOTIFICATION 12
-#define PW_EAP_SIM_ANY_ID_REQ 13
-#define PW_EAP_SIM_IDENTITY 14
-#define PW_EAP_SIM_VERSION_LIST 15
-#define PW_EAP_SIM_SELECTED_VERSION 16
-#define PW_EAP_SIM_FULLAUTH_ID_REQ 17
-#define PW_EAP_SIM_COUNTER 19
-#define PW_EAP_SIM_COUNTER_TOO_SMALL 20
-#define PW_EAP_SIM_NONCE_S 21
-#define PW_EAP_SIM_IV 129
-#define PW_EAP_SIM_ENCR_DATA 130
-#define PW_EAP_SIM_NEXT_PSEUDONUM 132
-#define PW_EAP_SIM_NEXT_REAUTH_ID 133
-#define PW_EAP_SIM_CHECKCODE 134
/*
* interfaces in eapsimlib.c
#define EAPSIM_SRES_SIZE 4
#define EAPSIM_RAND_SIZE 16
-#define EAPSIM_Kc_SIZE 8
+#define EAPSIM_KC_SIZE 8
#define EAPSIM_CALCMAC_SIZE 20
#define EAPSIM_NONCEMT_SIZE 16
#define EAPSIM_AUTH_SIZE 16
unsigned char nonce_mt[EAPSIM_NONCEMT_SIZE];
unsigned char rand[3][EAPSIM_RAND_SIZE];
unsigned char sres[3][EAPSIM_SRES_SIZE];
- unsigned char Kc[3][EAPSIM_Kc_SIZE];
+ unsigned char Kc[3][EAPSIM_KC_SIZE];
unsigned char versionlist[MAX_STRING_LEN];
unsigned char versionlistlen;
unsigned char versionselect[2];
SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_STORE, (void *)tls_conf->ocsp_store);
#endif
SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_SSN, (void *)ssn);
+ SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_TALLOC, (void *)tls_conf);
return talloc_steal(handler, ssn); /* ssn */
}
memcpy(&data_len, &eap_ds->response->type.data[1], 4);
data_len = ntohl(data_len);
if (data_len > MAX_RECORD_SIZE) {
- RDEBUG("The EAP-TLS packet will contain more data than we can process.");
+ RDEBUG("The EAP-TLS packet will contain more data than we can process");
talloc_free(tlspacket);
return NULL;
}
DEBUG2(" TLS: %d %d\n", data_len, tlspacket->length);
if (data_len < tlspacket->length) {
- RDEBUG("EAP-TLS packet claims to be smaller than the encapsulating EAP packet.");
+ RDEBUG("EAP-TLS packet claims to be smaller than the encapsulating EAP packet");
talloc_free(tlspacket);
return NULL;
}
*/
if (!tls_handshake_recv(handler->request, tls_session)) {
DEBUG2("TLS receive handshake failed during operation");
- eaptls_fail(handler, tls_session->peap_flag);
+ tls_fail(tls_session);
return FR_TLS_FAIL;
}
*/
if ((status == FR_TLS_MORE_FRAGMENTS) ||
(status == FR_TLS_MORE_FRAGMENTS_WITH_LENGTH) ||
- (status == FR_TLS_FIRST_FRAGMENT)) {
+ (status == FR_TLS_FIRST_FRAGMENT)) {
/*
* Send the ACK.
*/
* The EAP RFC's say 1020, but we're less picky.
*/
if (tls_conf->fragment_size < 100) {
- ERROR("Fragment size is too small.");
+ ERROR("Fragment size is too small");
return NULL;
}
* that can be devoted *solely* to EAP.
*/
if (tls_conf->fragment_size > 4000) {
- ERROR("Fragment size is too large.");
+ ERROR("Fragment size is too large");
return NULL;
}
#include <sys/time.h>
#include <arpa/inet.h>
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#endif
-
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
*/
fr_tls_status_t eaptls_process(eap_handler_t *handler);
-int eaptls_success(eap_handler_t *handler, int peap_flag);
-int eaptls_fail(eap_handler_t *handler, int peap_flag);
-int eaptls_request(EAP_DS *eap_ds, tls_session_t *ssn);
+int eaptls_success(eap_handler_t *handler, int peap_flag) CC_HINT(nonnull);
+int eaptls_fail(eap_handler_t *handler, int peap_flag) CC_HINT(nonnull);
+int eaptls_request(EAP_DS *eap_ds, tls_session_t *ssn) CC_HINT(nonnull);
/* MPPE key generation */
if (!packet->code) switch(reply->code) {
case PW_EAP_RESPONSE:
case PW_EAP_SUCCESS:
- packet->code = PW_AUTHENTICATION_ACK;
+ packet->code = PW_CODE_AUTHENTICATION_ACK;
rcode = RLM_MODULE_HANDLED;
break;
case PW_EAP_FAILURE:
- packet->code = PW_AUTHENTICATION_REJECT;
+ packet->code = PW_CODE_AUTHENTICATION_REJECT;
rcode = RLM_MODULE_REJECT;
break;
case PW_EAP_REQUEST:
- packet->code = PW_ACCESS_CHALLENGE;
+ packet->code = PW_CODE_ACCESS_CHALLENGE;
rcode = RLM_MODULE_HANDLED;
break;
default:
/* Should never enter here */
ERROR("rlm_eap: reply code %d is unknown, Rejecting the request.", reply->code);
- packet->code = PW_AUTHENTICATION_REJECT;
+ packet->code = PW_CODE_AUTHENTICATION_REJECT;
break;
}
ptr = (uint8_t const *) eap;
- paircursor(&out, &head);
+ fr_cursor_init(&out, &head);
do {
size = total;
if (size > 253) size = 253;
}
pairmemcpy(vp, ptr, size);
- pairinsert(&out, vp);
+ fr_cursor_insert(&out, vp);
ptr += size;
total -= size;
* Sanity check the length before doing anything.
*/
if (first->length < 4) {
- DEBUG("rlm_eap: EAP packet is too short.");
+ DEBUG("rlm_eap: EAP packet is too short");
return NULL;
}
* Take out even more weird things.
*/
if (len < 4) {
- DEBUG("rlm_eap: EAP packet has invalid length.");
+ DEBUG("rlm_eap: EAP packet has invalid length");
return NULL;
}
* Sanity check the length, BEFORE allocating memory.
*/
total_len = 0;
- paircursor(&cursor, &first);
- while ((i = pairfindnext(&cursor, PW_EAP_MESSAGE, 0, TAG_ANY))) {
+ fr_cursor_init(&cursor, &first);
+ while ((i = fr_cursor_next_by_num(&cursor, PW_EAP_MESSAGE, 0, TAG_ANY))) {
total_len += i->length;
if (total_len > len) {
ptr = (unsigned char *)eap_packet;
/* RADIUS ensures order of attrs, so just concatenate all */
- pairfirst(&cursor);
- while ((i = pairfindnext(&cursor, PW_EAP_MESSAGE, 0, TAG_ANY))) {
+ fr_cursor_first(&cursor);
+ while ((i = fr_cursor_next_by_num(&cursor, PW_EAP_MESSAGE, 0, TAG_ANY))) {
memcpy(ptr, i->vp_strvalue, i->length);
ptr += i->length;
}
p = buf;
memcpy(p, ek->identity, ek->identitylen); p = p+ek->identitylen;
- memcpy(p, ek->Kc[0], EAPSIM_Kc_SIZE); p = p+EAPSIM_Kc_SIZE;
- memcpy(p, ek->Kc[1], EAPSIM_Kc_SIZE); p = p+EAPSIM_Kc_SIZE;
- memcpy(p, ek->Kc[2], EAPSIM_Kc_SIZE); p = p+EAPSIM_Kc_SIZE;
+ memcpy(p, ek->Kc[0], EAPSIM_KC_SIZE); p = p+EAPSIM_KC_SIZE;
+ memcpy(p, ek->Kc[1], EAPSIM_KC_SIZE); p = p+EAPSIM_KC_SIZE;
+ memcpy(p, ek->Kc[2], EAPSIM_KC_SIZE); p = p+EAPSIM_KC_SIZE;
memcpy(p, ek->nonce_mt, sizeof(ek->nonce_mt)); p=p+sizeof(ek->nonce_mt);
memcpy(p, ek->versionlist, ek->versionlistlen);p=p+ek->versionlistlen;
memcpy(p, ek->versionselect, sizeof(ek->versionselect)); p=p+sizeof(ek->versionselect);
{
unsigned int i, j, k;
- j=0; k=0;
-
printf("Input was: \n");
printf(" identity: (len=%d)", ek->identitylen);
for (i = 0; i < ek->identitylen; i++) {
for (k = 0; k<3; k++) {
printf("\n Kc%d: ", k);
- for (i = 0; i < EAPSIM_Kc_SIZE; i++) {
+ for (i = 0; i < EAPSIM_KC_SIZE; i++) {
printf("%02x", ek->Kc[k][i]);
}
}
printf("\n\nOutput\n");
printf("mk: ");
- j=0; k=0;
+ j=0;
for (i = 0; i < sizeof(ek->master_key); i++) {
if(j==4) {
printf("_");
}
printf("\nK_aut: ");
- j=0; k=0;
+ j=0;
for (i = 0; i < sizeof(ek->K_aut); i++) {
if(j==4) {
printf("_");
}
printf("\nK_encr: ");
- j=0; k=0;
+ j=0;
for (i = 0; i < sizeof(ek->K_encr); i++) {
if(j==4) {
printf("_");
* that we need to encode all of this.
*/
encoded_size = 0;
- for (vp = paircursor(&cursor, &r->vps);
+ for (vp = fr_cursor_init(&cursor, &r->vps);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
int roundedlen;
int vplen;
* attribute, we pull the contents out, save it for later
* processing, set the size to 16 bytes (plus 2 bytes padding).
*
- * At this point, we only care about the size.
+ * At this point, we only care about the size.
*/
if(vp->da->attr == ATTRIBUTE_EAP_SIM_BASE + PW_EAP_SIM_MAC) {
vplen = 18;
*/
attr = encodedmsg+3;
- for (vp = pairfirst(&cursor); vp; vp = pairnext(&cursor)) {
+ for (vp = fr_cursor_first(&cursor); vp; vp = fr_cursor_next(&cursor)) {
int roundedlen;
if(vp->da->attr < ATTRIBUTE_EAP_SIM_BASE ||
* attribute, we pull the contents out, save it for later
* processing, set the size to 16 bytes (plus 2 bytes padding).
*
- * At this point, we put in zeros, and remember where the
+ * At this point, we put in zeros, and remember where the
* sixteen bytes go.
*/
if(vp->da->attr == ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_MAC) {
fr_hmac_sha1(buffer, hmaclen, vp->vp_octets, vp->length, sha1digest);
/* done with the buffer, free it */
- free(buffer);
+ talloc_free(buffer);
/* now copy the digest to where it belongs in the AT_MAC */
/* note that it is truncated to 128-bits */
*/
attr = buffer+8;
while(attr < (buffer+elen)) {
- if(attr[0] == PW_EAP_SIM_MAC) {
+ if (attr[0] == (PW_EAP_SIM_MAC - PW_EAP_SIM_BASE)) {
/* zero the data portion, after making sure
* the size is >=5. Maybe future versions.
* will use more bytes, so be liberal.
/* b. w_0 = SHA1(XVAL) */
fr_SHA1Init(&context);
- memset(zeros, 0, sizeof(zeros));
+ memset(zeros + 20, 0, sizeof(zeros) - 20);
memcpy(zeros, xval.p, 20);
#ifndef WITH_OPENSSL_SHA1
fr_SHA1Transform(context.state, zeros);
/* e. w_1 = SHA1(XVAL) */
fr_SHA1Init(&context);
- memset(zeros, 0, sizeof(zeros));
+ memset(zeros + 20, 0, sizeof(zeros) - 20);
memcpy(zeros, xval.p, 20);
#ifndef WITH_OPENSSL_SHA1
fr_SHA1Transform(context.state, zeros);
size_t prf_size;
if (!s->s3) {
- EDEBUG("No SSLv3 information");
+ ERROR("No SSLv3 information");
return;
}
uint8_t *p = seed;
if (!s->s3) {
- EDEBUG("No SSLv3 information");
+ ERROR("No SSLv3 information");
return;
}
uint8_t *p;
if (!s->s3) {
- EDEBUG("No SSLv3 information");
+ ERROR("No SSLv3 information");
return;
}
static int check_opaque_free(check_handler_t *check)
{
- int do_warning = false;
+ bool do_warning = false;
uint8_t state[8];
if (!check->inst || !check->handler) {
PTHREAD_MUTEX_UNLOCK(&(check->inst->handler_mutex));
if (do_warning) {
- WDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
- WDEBUG("!! EAP session with state 0x%02x%02x%02x%02x%02x%02x%02x%02x did not finish! !!",
+ WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ WARN("!! EAP session with state 0x%02x%02x%02x%02x%02x%02x%02x%02x did not finish! !!",
state[0], state[1],
state[2], state[3],
state[4], state[5],
state[6], state[7]);
- WDEBUG("!! Please read http://wiki.freeradius.org/guide/Certificate_Compatibility !!");
- WDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ WARN("!! Please read http://wiki.freeradius.org/guide/Certificate_Compatibility !!");
+ WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
return 0;
{
eap_handler_t *node, *next;
- for (node = inst->session_head; node != NULL; node = next) {
+ for (node = inst->session_head; node != NULL; node = next) {
next = node->next;
talloc_free(node);
}
* Expire entries from the start of the list.
* They should be the oldest ones.
*/
- if ((timestamp - handler->timestamp) > inst->timer_limit) {
+ if ((timestamp - handler->timestamp) > (int)inst->timer_limit) {
rbnode_t *node;
node = rbtree_find(inst->session_tree, handler);
rad_assert(node != NULL);
VALUE_PAIR *state;
REQUEST *request = handler->request;
- rad_assert(handler != NULL);
- rad_assert(request != NULL);
-
/*
* Generate State, since we've been asked to add it to
* the list.
static char const *secret = NULL;
static int do_output = 1;
static int do_summary = 0;
-static int filedone = 0;
+static bool filedone = false;
static int totalapp = 0;
static int totaldeny = 0;
static char filesecret[256];
char const *radius_dir = NULL;
+char const *dict_dir = NULL;
char const *progname = "radeapclient";
/* fr_randctx randctx; */
+struct main_config_t main_config;
+char const *radiusd_version = "";
+
#ifdef WITH_TLS
#include <freeradius-devel/tls.h>
#endif
fprintf(stderr, "Usage: radeapclient [options] server[:port] <command> [<secret>]\n");
fprintf(stderr, " <command> One of auth, acct, status, or disconnect.\n");
- fprintf(stderr, " -c count Send each packet 'count' times.\n");
fprintf(stderr, " -d raddb Set dictionary directory.\n");
fprintf(stderr, " -f file Read packets from file, not stdin.\n");
fprintf(stderr, " -r retries If timeout, retry sending the packet 'retries' times.\n");
exit(1);
}
-int radlog(log_type_t lvl, char const *fmt, ...)
+int radlog(UNUSED log_type_t lvl, char const *fmt, ...)
{
va_list ap;
int r;
- r = lvl; /* shut up compiler */
-
va_start(ap, fmt);
r = vfprintf(stderr, fmt, ap);
va_end(ap);
return r;
}
-void radlog_request(UNUSED log_type_t lvl, UNUSED log_debug_t priority,
- UNUSED REQUEST *request, char const *msg, ...)
+void vradlog_request(UNUSED log_type_t lvl, UNUSED log_debug_t priority,
+ UNUSED REQUEST *request, char const *msg, va_list ap)
{
- va_list ap;
-
- va_start(ap, msg);
vfprintf(stderr, msg, ap);
- va_end(ap);
fputc('\n', stderr);
}
-static int getport(char const *name)
+static uint16_t getport(char const *name)
{
struct servent *svp;
char buffer[1024];
char const *received, *from;
fr_ipaddr_t const *ip;
- int port;
+ uint16_t port;
if (!packet) return;
*
* This really belongs in a utility library
*/
- if ((packet->code > 0) && (packet->code < FR_MAX_PACKET_CODE)) {
+ if (is_radius_code(packet->code)) {
printf("%s %s packet %s host %s port %d, id=%d, length=%d\n",
received, fr_packet_codes[packet->code], from,
inet_ntop(ip->af, &ip->ipaddr, buffer, sizeof(buffer)),
int i;
struct timeval tv;
+ if (!req || !rep || !*rep) return -1;
+
for (i = 0; i < retries; i++) {
fd_set rdfdesc;
debug_packet(req, R_SENT);
- rad_send(req, NULL, secret);
+ if (rad_send(req, NULL, secret) < 0) {
+ fr_perror("radeapclient");
+ exit(1);
+ }
/* And wait for reply, timing out as necessary */
FD_ZERO(&rdfdesc);
}
break;
} else { /* NULL: couldn't receive the packet */
- fr_perror("radclient:");
+ fr_perror("radclient");
exit(1);
}
}
*
* Hmm... we should really be using eapol_test, which does
* a lot more than radeapclient.
- */
+ */
if (rad_verify(*rep, req, secret) != 0) {
fr_perror("rad_verify");
exit(1);
if (!fr_debug_flag && do_output) {
debug_packet(*rep, R_RECV);
}
- if((*rep)->code == PW_AUTHENTICATION_ACK) {
+ if((*rep)->code == PW_CODE_AUTHENTICATION_ACK) {
totalapp++;
- } else if ((*rep)->code == PW_AUTHENTICATION_REJECT) {
+ } else if ((*rep)->code == PW_CODE_AUTHENTICATION_REJECT) {
totaldeny++;
}
pairreplace(&(rep->vps), newvp);
/* insert selected version into response. */
- newvp = paircreate(rep, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_SELECTED_VERSION, 0);
- versions = (uint16_t const *)newvp->vp_strvalue;
- versions[0] = htons(selectedversion);
- newvp->length = 2;
- pairreplace(&(rep->vps), newvp);
+ {
+ uint16_t no_versions;
+
+ no_versions = htons(selectedversion);
+
+ newvp = paircreate(rep, ATTRIBUTE_EAP_SIM_BASE + PW_EAP_SIM_SELECTED_VERSION, 0);
+ pairmemcpy(newvp, (uint8_t *) &no_versions, 2);
+ pairreplace(&(rep->vps), newvp);
- /* record the selected version */
- memcpy(eapsim_mk.versionselect, (unsigned char const *)versions, 2);
+ /* record the selected version */
+ memcpy(eapsim_mk.versionselect, &no_versions, 2);
+ }
vp = newvp = NULL;
{
uint32_t nonce[4];
+ uint8_t *p;
/*
* insert a nonce_mt that we make up.
*/
- newvp = paircreate(rep, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_NONCE_MT, 0);
- newvp->vp_octets[0]=0;
- newvp->vp_octets[1]=0;
- newvp->length = 18; /* 16 bytes of nonce + padding */
-
nonce[0]=fr_rand();
nonce[1]=fr_rand();
nonce[2]=fr_rand();
nonce[3]=fr_rand();
- memcpy(&newvp->vp_octets[2], nonce, 16);
+
+ newvp = paircreate(rep, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_NONCE_MT, 0);
+
+ p = talloc_zero_array(newvp, uint8_t, 18); /* 18 = 16 bytes of nonce + padding */
+ memcpy(&p[2], nonce, 16);
+ pairmemsteal(newvp, p);
+
pairreplace(&(rep->vps), newvp);
/* also keep a copy of the nonce! */
}
{
- uint16_t *pidlen, idlen;
+ uint16_t idlen;
+ uint8_t *p;
+ uint16_t no_idlen;
/*
* insert the identity here.
return 0;
}
newvp = paircreate(rep, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_IDENTITY, 0);
+
idlen = strlen(vp->vp_strvalue);
- pidlen = (uint16_t *)newvp->vp_strvalue;
- *pidlen = htons(idlen);
- newvp->length = idlen + 2;
+ p = talloc_zero_array(newvp, uint8_t, idlen + 2);
+ no_idlen = htons(idlen);
+ memcpy(p, &no_idlen, 2);
+ memcpy(p + 2, vp->vp_strvalue, idlen);
+ pairmemsteal(newvp, p);
- memcpy(&newvp->vp_strvalue[2], vp->vp_strvalue, idlen);
pairreplace(&(rep->vps), newvp);
/* record it */
*/
{
VALUE_PAIR *randcfgvp[3];
- uint8_t *randcfg[3];
+ uint8_t const *randcfg[3];
randcfg[0] = &randvp->vp_octets[2];
randcfg[1] = &randvp->vp_octets[2+EAPSIM_RAND_SIZE];
newvp->vp_integer = eapsim_challenge;
pairreplace(&(rep->vps), newvp);
- /*
- * fill the SIM_MAC with a field that will in fact get appended
- * to the packet before the MAC is calculated
- */
- newvp = paircreate(rep, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_MAC, 0);
- memcpy(newvp->vp_strvalue+EAPSIM_SRES_SIZE*0, sres1->vp_strvalue, EAPSIM_SRES_SIZE);
- memcpy(newvp->vp_strvalue+EAPSIM_SRES_SIZE*1, sres2->vp_strvalue, EAPSIM_SRES_SIZE);
- memcpy(newvp->vp_strvalue+EAPSIM_SRES_SIZE*2, sres3->vp_strvalue, EAPSIM_SRES_SIZE);
- newvp->length = EAPSIM_SRES_SIZE*3;
- pairreplace(&(rep->vps), newvp);
+ {
+ uint8_t *p;
+ /*
+ * fill the SIM_MAC with a field that will in fact get appended
+ * to the packet before the MAC is calculated
+ */
+ newvp = paircreate(rep, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_MAC, 0);
+
+ p = talloc_zero_array(newvp, uint8_t, EAPSIM_SRES_SIZE*3);
+ memcpy(p+EAPSIM_SRES_SIZE * 0, sres1->vp_strvalue, EAPSIM_SRES_SIZE);
+ memcpy(p+EAPSIM_SRES_SIZE * 1, sres2->vp_strvalue, EAPSIM_SRES_SIZE);
+ memcpy(p+EAPSIM_SRES_SIZE * 2, sres3->vp_strvalue, EAPSIM_SRES_SIZE);
+ pairmemsteal(newvp, p);
+
+ pairreplace(&(rep->vps), newvp);
+ }
newvp = paircreate(rep, ATTRIBUTE_EAP_SIM_KEY, 0);
- memcpy(newvp->vp_strvalue, eapsim_mk.K_aut, EAPSIM_AUTH_SIZE);
- newvp->length = EAPSIM_AUTH_SIZE;
+ pairmemcpy(newvp, eapsim_mk.K_aut, EAPSIM_AUTH_SIZE);
+
pairreplace(&(rep->vps), newvp);
return 1;
RADIUS_PACKET *rep)
{
VALUE_PAIR *vp, *id, *state;
- size_t valuesize, namesize;
+ size_t valuesize;
uint8_t identifier;
uint8_t const *value;
- uint8_t const *name;
FR_MD5_CTX context;
uint8_t response[16];
/* got the details of the MD5 challenge */
valuesize = vp->vp_octets[0];
value = &vp->vp_octets[1];
- name = &vp->vp_octets[valuesize+1];
- namesize = vp->length - (valuesize + 1);
/* sanitize items */
if(valuesize > vp->length)
fr_MD5Update(&context, value, valuesize);
fr_MD5Final(response, &context);
- vp = paircreate(rep, ATTRIBUTE_EAP_BASE+PW_EAP_MD5, 0);
- vp->vp_octets[0]=16;
- memcpy(&vp->vp_strvalue[1], response, 16);
- vp->length = 17;
+ {
+ uint8_t *p;
+ uint8_t lg_response;
+
+ vp = paircreate(rep, ATTRIBUTE_EAP_BASE+PW_EAP_MD5, 0);
+ vp->length = 17;
+ p = talloc_zero_array(vp, uint8_t, 17);
+ lg_response = 16;
+ memcpy(p, &lg_response, 1);
+ memcpy(p + 1, response, 16);
+ pairmemsteal(vp, p);
+ }
pairreplace(&(rep->vps), vp);
pairreplace(&(rep->vps), id);
VALUE_PAIR *vp, *vpnext;
int tried_eap_md5 = 0;
- if (vp->length > sizeof(password)) {
- fprintf(stderr, "radeapclient: Password buffer too small have %zu bytes need %zu bytes\n",
- sizeof(password), vp->length);
- return 0;
- }
+ if (!rep) return -1;
+
/*
* Keep a copy of the the User-Password attribute.
*/
case PW_DIGEST_NONCE_COUNT:
case PW_DIGEST_USER_NAME:
/* overlapping! */
- memmove(&vp->vp_strvalue[2], &vp->vp_octets[0], vp->length);
- vp->vp_octets[0] = vp->da->attr - PW_DIGEST_REALM + 1;
- vp->length += 2;
- vp->vp_octets[1] = vp->length;
- vp->da->attr = PW_DIGEST_ATTRIBUTES;
+ {
+ DICT_ATTR const *da;
+ uint8_t *p, *q;
+
+ p = talloc_array(vp, uint8_t, vp->length + 2);
+
+ memcpy(p + 2, vp->vp_octets, vp->length);
+ p[0] = vp->da->attr - PW_DIGEST_REALM + 1;
+ vp->length += 2;
+ p[1] = vp->length;
+
+ da = dict_attrbyvalue(PW_DIGEST_ATTRIBUTES, 0);
+ vp->da = da;
+
+ /*
+ * Re-do pairmemsteal ourselves,
+ * because we play games with
+ * vp->da, and pairmemsteal goes
+ * to GREAT lengths to sanitize
+ * and fix and change and
+ * double-check the various
+ * fields.
+ */
+ memcpy(&q, &vp->vp_octets, sizeof(q));
+ talloc_free(q);
+
+ vp->vp_octets = talloc_steal(vp, p);
+ vp->type = VT_DATA;
+
+ VERIFY_VP(vp);
+ }
break;
}
}
} else if ((vp = pairfind(rep->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) != NULL) {
pairstrcpy(vp, password);
- rad_chap_encode(rep, vp->vp_octets, rep->id, vp);
- vp->length = 17;
+ uint8_t *p;
+ p = talloc_zero_array(vp, uint8_t, 17);
+ rad_chap_encode(rep, p, rep->id, vp);
+ pairmemsteal(vp, p);
}
} /* there WAS a password */
/* send the response, wait for the next request */
send_packet(rep, &req);
+ if (!req) return -1;
+
/* okay got back the packet, go and decode the EAP-Message. */
unmap_eap_methods(req);
}
+void set_radius_dir(TALLOC_CTX *ctx, char const *path)
+{
+ if (radius_dir) {
+ char *p;
+
+ memcpy(&p, &radius_dir, sizeof(p));
+ talloc_free(p);
+ radius_dir = NULL;
+ }
+ if (path) radius_dir = talloc_strdup(ctx, path);
+}
+
+
int main(int argc, char **argv)
{
RADIUS_PACKET *req;
char *p;
int c;
- int port = 0;
+ uint16_t port = 0;
char *filename = NULL;
FILE *fp;
- int count = 1;
int id;
int force_af = AF_UNSPEC;
+ /*
+ * We probably don't want to free the talloc autofree context
+ * directly, so we'll allocate a new context beneath it, and
+ * free that before any leak reports.
+ */
+ TALLOC_CTX *autofree = talloc_init("main");
+
id = ((int)getpid() & 0xff);
fr_debug_flag = 0;
radlog_dest = L_DST_STDERR;
- while ((c = getopt(argc, argv, "46c:d:f:hi:qst:r:S:xXv")) != EOF)
+ set_radius_dir(autofree, RADIUS_DIR);
+
+ while ((c = getopt(argc, argv, "46c:d:D:f:hi:qst:r:S:xXv")) != EOF)
{
switch(c) {
case '4':
case '6':
force_af = AF_INET6;
break;
- case 'c':
- if (!isdigit((int) *optarg))
- usage();
- count = atoi(optarg);
- break;
case 'd':
- radius_dir = strdup(optarg);
+ set_radius_dir(autofree, optarg);
+ break;
+ case 'D':
+ main_config.dictionary_dir = talloc_typed_strdup(NULL, optarg);
break;
case 'f':
filename = optarg;
timeout = atof(optarg);
break;
case 'v':
- printf("radclient: $Id$ built on " __DATE__ " at " __TIME__ "\n");
+ printf("radeapclient: $Id$ built on " __DATE__ " at " __TIME__ "\n");
exit(0);
break;
case 'S':
fp = fopen(optarg, "r");
if (!fp) {
fprintf(stderr, "radclient: Error opening %s: %s\n",
- optarg, strerror(errno));
+ optarg, fr_syserror(errno));
exit(1);
}
if (fgets(filesecret, sizeof(filesecret), fp) == NULL) {
fprintf(stderr, "radclient: Error reading %s: %s\n",
- optarg, strerror(errno));
+ optarg, fr_syserror(errno));
exit(1);
}
fclose(fp);
usage();
}
- if (!radius_dir) radius_dir = strdup(RADDBDIR);
+ if (!main_config.dictionary_dir) {
+ main_config.dictionary_dir = DICTDIR;
+ }
- if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) {
- fr_perror("radclient");
- return 1;
+ /*
+ * Read the distribution dictionaries first, then
+ * the ones in raddb.
+ */
+ DEBUG2("including dictionary file %s/%s", main_config.dictionary_dir, RADIUS_DICTIONARY);
+ if (dict_init(main_config.dictionary_dir, RADIUS_DICTIONARY) != 0) {
+ ERROR("Errors reading dictionary: %s",
+ fr_strerror());
+ exit(1);
+ }
+
+ /*
+ * It's OK if this one doesn't exist.
+ */
+ int rcode = dict_read(radius_dir, RADIUS_DICTIONARY);
+ if (rcode == -1) {
+ ERROR("Errors reading %s/%s: %s", radius_dir, RADIUS_DICTIONARY,
+ fr_strerror());
+ exit(1);
+ }
+
+ /*
+ * We print this after reading it. That way if
+ * it doesn't exist, it's OK, and we don't print
+ * anything.
+ */
+ if (rcode == 0) {
+ DEBUG2("including dictionary file %s/%s", radius_dir, RADIUS_DICTIONARY);
}
req = rad_alloc(NULL, 1);
portname = NULL;
}
- if (ip_hton(hostname, force_af, &req->dst_ipaddr) < 0) {
- fprintf(stderr, "radclient: Failed to find IP address for host %s: %s\n", hostname, strerror(errno));
+ if (ip_hton(&req->dst_ipaddr, force_af, hostname, false) < 0) {
+ fprintf(stderr, "radclient: Failed to find IP address for host %s: %s\n", hostname, fr_syserror(errno));
exit(1);
}
if (strcmp(argv[2], "auth") == 0) {
if (port == 0) port = getport("radius");
if (port == 0) port = PW_AUTH_UDP_PORT;
- req->code = PW_AUTHENTICATION_REQUEST;
+ req->code = PW_CODE_AUTHENTICATION_REQUEST;
} else if (strcmp(argv[2], "acct") == 0) {
if (port == 0) port = getport("radacct");
if (port == 0) port = PW_ACCT_UDP_PORT;
- req->code = PW_ACCOUNTING_REQUEST;
+ req->code = PW_CODE_ACCOUNTING_REQUEST;
do_summary = 0;
} else if (strcmp(argv[2], "status") == 0) {
if (port == 0) port = getport("radius");
if (port == 0) port = PW_AUTH_UDP_PORT;
- req->code = PW_STATUS_SERVER;
+ req->code = PW_CODE_STATUS_SERVER;
} else if (strcmp(argv[2], "disconnect") == 0) {
if (port == 0) port = PW_POD_UDP_PORT;
- req->code = PW_DISCONNECT_REQUEST;
+ req->code = PW_CODE_DISCONNECT_REQUEST;
} else if (isdigit((int) argv[2][0])) {
if (port == 0) port = getport("radius");
fp = fopen(filename, "r");
if (!fp) {
fprintf(stderr, "radclient: Error opening %s: %s\n",
- filename, strerror(errno));
+ filename, fr_syserror(errno));
exit(1);
}
} else {
}
while(!filedone) {
- if(req->vps) pairfree(&req->vps);
-
- if ((req->vps = readvp2(NULL, fp, &filedone, "radeapclient:"))
- == NULL) {
+ if (req->vps) pairfree(&req->vps);
+ if (readvp2(&req->vps, NULL, fp, &filedone) < 0) {
+ fr_perror("radeapclient");
break;
}
sendrecv_eap(req);
}
- free(radius_dir);
if(do_summary) {
printf("\n\t Total approved auths: %d\n", totalapp);
printf("\t Total denied auths: %d\n", totaldeny);
}
+
+ talloc_free(autofree);
+
return 0;
}
{
VALUE_PAIR *vp, *vpnext;
int id, eapcode;
- eap_packet_t ep;
int eap_method;
+ eap_packet_t *pt_ep = talloc_zero(req, eap_packet_t);
+
vp = pairfind(req->vps, ATTRIBUTE_EAP_ID, 0, TAG_ANY);
if(!vp) {
id = ((int)getpid() & 0xff);
eapcode = vp->vp_integer;
}
-
for(vp = req->vps; vp != NULL; vp = vpnext) {
/* save it in case it changes! */
vpnext = vp->next;
/* nuke any existing EAP-Messages */
pairdelete(&req->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
- memset(&ep, 0, sizeof(ep));
- ep.code = eapcode;
- ep.id = id;
- ep.type.num = eap_method;
- ep.type.length = vp->length;
- ep.type.data = vp->vp_octets; /* no need for copy */
- eap_basic_compose(req, &ep);
+ pt_ep->code = eapcode;
+ pt_ep->id = id;
+ pt_ep->type.num = eap_method;
+ pt_ep->type.length = vp->length;
+
+ pt_ep->type.data = talloc_memdup(vp, vp->vp_octets, vp->length);
+ talloc_set_type(pt_ep->type.data, uint8_t);
+
+ eap_basic_compose(req, pt_ep);
}
}
int len;
int type;
+ if (!rep) return;
+
/* find eap message */
e = eap_vp2packet(NULL, rep->vps);
type += ATTRIBUTE_EAP_BASE;
len -= 5;
- if(len > MAX_STRING_LEN) {
+ if (len > MAX_STRING_LEN) {
len = MAX_STRING_LEN;
}
eap1 = paircreate(rep, type, 0);
- memcpy(eap1->vp_strvalue, &e->data[1], len);
- eap1->length = len;
+ pairmemcpy(eap1, e->data + 1, len);
+
pairadd(&(rep->vps), eap1);
break;
}
static int map_eapsim_types(RADIUS_PACKET *r)
{
- eap_packet_t ep;
int ret;
- memset(&ep, 0, sizeof(ep));
- ret = map_eapsim_basictypes(r, &ep);
+ eap_packet_t *pt_ep = talloc_zero(r, eap_packet_t);
+
+ ret = map_eapsim_basictypes(r, pt_ep);
+
if(ret != 1) {
return ret;
}
- eap_basic_compose(r, &ep);
+
+ eap_basic_compose(r, pt_ep);
return 1;
}
static int unmap_eapsim_types(RADIUS_PACKET *r)
{
VALUE_PAIR *esvp;
+ uint8_t *eap_data;
+ int rcode_unmap;
esvp = pairfind(r->vps, ATTRIBUTE_EAP_BASE+PW_EAP_SIM, 0, TAG_ANY);
if (!esvp) {
return 0;
}
- return unmap_eapsim_basictypes(r, esvp->vp_octets, esvp->length);
+ eap_data = talloc_memdup(esvp, esvp->vp_octets, esvp->length);
+ talloc_set_type(eap_data, uint8_t);
+
+ rcode_unmap = unmap_eapsim_basictypes(r, eap_data, esvp->length);
+
+ talloc_free(eap_data);
+ return rcode_unmap;
}
#ifdef TEST_CASE
}
while(!filedone) {
- if(req->vps) pairfree(&req->vps);
- if(req2->vps) pairfree(&req2->vps);
+ if (req->vps) pairfree(&req->vps);
+ if (req2->vps) pairfree(&req2->vps);
- if ((req->vps = readvp2(NULL, stdin, &filedone, "eapsimlib:")) == NULL) {
+ if (readvp2(&req->vps, NULL, stdin, &filedone) < 0) {
+ fr_perror("radeapclient");
break;
}
-TARGET :=
+TARGET := radeapclient
SOURCES := radeapclient.c
+SOURCES += ${top_srcdir}/src/main/files.c \
+ ${top_srcdir}/src/main/threads.c \
+ ${top_srcdir}/src/main/version.c
+
+TGT_PREREQS := libfreeradius-radius.a libfreeradius-server.a
+TGT_LDLIBS := $(LIBS)
+
+#
+# For future work, if we want radeapclient to become radclient
+#
+ifneq "$(filter libfreeradius-eap%,${ALL_TGTS})" ""
+TGT_PREREQS += libfreeradius-eap.a
+
ifneq ($(OPENSSL_LIBS),)
SOURCES += ${top_srcdir}/src/main/cb.c ${top_srcdir}/src/main/tls.c
+TGT_LDLIBS += $(OPENSSL_LIBS)
endif
-TGT_PREREQS := libfreeradius-radius.a libfreeradius-eap.a
-TGT_LDLIBS := $(LIBS)
-
-SRC_INCDIRS := libeap
+SRC_CFLAGS += -DWITH_EAPCLIENT
+SRC_INCDIRS := ${top_srcdir}/src/modules/rlm_eap/libeap
+endif
#include "rlm_eap.h"
static const CONF_PARSER module_config[] = {
- { "default_eap_type", PW_TYPE_STRING_PTR,
- offsetof(rlm_eap_t, default_method_name), NULL, "md5" },
- { "timer_expire", PW_TYPE_INTEGER,
- offsetof(rlm_eap_t, timer_limit), NULL, "60"},
- { "ignore_unknown_eap_types", PW_TYPE_BOOLEAN,
- offsetof(rlm_eap_t, ignore_unknown_types), NULL, "no" },
- { "mod_accounting_username_bug", PW_TYPE_BOOLEAN,
- offsetof(rlm_eap_t, mod_accounting_username_bug), NULL, "no" },
- { "max_sessions", PW_TYPE_INTEGER,
- offsetof(rlm_eap_t, max_sessions), NULL, "2048"},
-
- { NULL, -1, 0, NULL, NULL } /* end the list */
+ { "default_eap_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_t, default_method_name), "md5" },
+ { "timer_expire", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_t, timer_limit), "60" },
+ { "ignore_unknown_eap_types", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_t, ignore_unknown_types), "no" },
+ { "mod_accounting_username_bug", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_t, mod_accounting_username_bug), "no" },
+ { "max_sessions", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_t, max_sessions), "2048" },
+
+ { NULL, -1, 0, NULL, NULL } /* end the list */
};
/*
#endif
rbtree_free(inst->session_tree);
- if (inst->handler_tree) rbtree_free(inst->handler_tree);
+ if (inst->handler_tree) {
+ rbtree_free(inst->handler_tree);
+ /*
+ * Must be NULL else when nodes are freed they try to
+ * delete themselves from the tree.
+ */
+ inst->handler_tree = NULL;
+ }
inst->session_tree = NULL;
eaplist_free(inst);
* EAP work.
*/
if (fr_ipaddr_cmp(&one->src_ipaddr, &two->src_ipaddr) != 0) {
- WDEBUG("EAP packets are arriving from two different upstream "
+ WARN("EAP packets are arriving from two different upstream "
"servers. Has there been a proxy fail-over?");
}
#ifdef HAVE_PTHREAD_H
if (pthread_mutex_init(&(inst->handler_mutex), NULL) < 0) {
- ERROR("rlm_eap (%s): Failed initializing mutex: %s", inst->xlat_name, strerror(errno));
+ ERROR("rlm_eap (%s): Failed initializing mutex: %s", inst->xlat_name, fr_syserror(errno));
return -1;
}
#endif
#ifdef HAVE_PTHREAD_H
if (pthread_mutex_init(&(inst->session_mutex), NULL) < 0) {
- ERROR("rlm_eap (%s): Failed initializing mutex: %s", inst->xlat_name, strerror(errno));
+ ERROR("rlm_eap (%s): Failed initializing mutex: %s", inst->xlat_name, fr_syserror(errno));
return -1;
}
#endif
/*
* For backwards compatibility.
*/
-static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
{
rlm_eap_t *inst;
eap_handler_t *handler;
/*
* If we're doing horrible tunneling work, remember it.
*/
- if ((request->options & RAD_REQUEST_OPTION_PROXY_EAP) != 0) {
- RDEBUG2(" Not-EAP proxy set. Not composing EAP");
+ if ((request->log.lvl & RAD_REQUEST_OPTION_PROXY_EAP) != 0) {
+ RDEBUG2("No EAP proxy set. Not composing EAP");
/*
* Add the handle to the proxied list, so that we
* can retrieve it in the post-proxy stage, and
*/
pairdelete(&request->proxy->vps, PW_FREERADIUS_PROXIED_TO, VENDORPEC_FREERADIUS, TAG_ANY);
- RDEBUG2(" Tunneled session will be proxied. Not doing EAP.");
+ RDEBUG2("Tunneled session will be proxied. Not doing EAP");
return RLM_MODULE_HANDLED;
}
#endif
* says that we MUST include a User-Name attribute in the
* Access-Accept.
*/
- if ((request->reply->code == PW_AUTHENTICATION_ACK) &&
+ if ((request->reply->code == PW_CODE_AUTHENTICATION_ACK) &&
request->username) {
VALUE_PAIR *vp;
* terminated string in Access-Accept.
*/
if (inst->mod_accounting_username_bug) {
- char const *old = vp->vp_strvalue;
- char *new = talloc_zero_array(vp, char, vp->length + 1);
+ char const *old = vp->vp_strvalue;
+ char *new = talloc_zero_array(vp, char, vp->length + 1);
- memcpy(new, old, vp->length);
- vp->vp_strvalue = new;
- vp->length++;
+ memcpy(new, old, vp->length);
+ vp->vp_strvalue = new;
+ vp->length++;
- rad_const_free(old);
+ rad_const_free(old);
}
}
* to check for user existence & get their configured values.
* It Handles EAP-START Messages, User-Name initilization.
*/
-static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
{
rlm_eap_t *inst;
int status;
* If we're proxying EAP, then there may be magic we need
* to do.
*/
-static rlm_rcode_t mod_post_proxy(void *inst, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_post_proxy(void *inst, REQUEST *request)
{
size_t i;
size_t len;
* says that we MUST include a User-Name attribute in the
* Access-Accept.
*/
- if ((request->reply->code == PW_AUTHENTICATION_ACK) &&
+ if ((request->reply->code == PW_CODE_AUTHENTICATION_ACK) &&
request->username) {
/*
* Doesn't exist, add it in.
}
/*
+ * This is allowed.
+ */
+ if (!request->proxy_reply) return RLM_MODULE_NOOP;
+
+ /*
* There may be more than one Cisco-AVPair.
* Ensure we find the one with the LEAP attribute.
*/
- paircursor(&cursor, &request->proxy_reply->vps);
+ fr_cursor_init(&cursor, &request->proxy_reply->vps);
for (;;) {
/*
* Hmm... there's got to be a better way to
* This is vendor Cisco (9), Cisco-AVPair
* attribute (1)
*/
- vp = pairfindnext(&cursor, 1, 9, TAG_ANY);
+ vp = fr_cursor_next_by_num(&cursor, 1, 9, TAG_ANY);
if (!vp) {
return RLM_MODULE_NOOP;
}
* The format is very specific.
*/
if (vp->length != (17 + 34)) {
- RDEBUG2("Cisco-AVPair with leap:session-key has incorrect length %d: Expected %d",
+ RDEBUG2("Cisco-AVPair with leap:session-key has incorrect length %zu: Expected %d",
vp->length, 17 + 34);
return RLM_MODULE_NOOP;
}
*/
i = 34;
p = talloc_memdup(vp, vp->vp_octets, vp->length);
- len = rad_tunnel_pwdecode((uint8_t *)p + 17, &i,
- request->home_server->secret,
- request->proxy->vector);
+ talloc_set_type(p, uint8_t);
+ len = rad_tunnel_pwdecode((uint8_t *)p + 17, &i, request->home_server->secret, request->proxy->vector);
/*
* FIXME: Assert that i == 16.
}
#endif
-static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
{
rlm_eap_t *inst = instance;
VALUE_PAIR *vp;
module_t rlm_eap = {
RLM_MODULE_INIT,
"eap",
- RLM_TYPE_CHECK_CONFIG_SAFE, /* type */
+ 0, /* type */
sizeof(rlm_eap_t),
module_config,
mod_instantiate, /* instantiation */
/*
* Configuration items.
*/
- int timer_limit;
+ uint32_t timer_limit;
char const *default_method_name;
eap_type_t default_method;
bool ignore_unknown_types;
bool mod_accounting_username_bug;
- int max_sessions;
+ uint32_t max_sessions;
#ifdef HAVE_PTHREAD_H
pthread_mutex_t session_mutex;
/* function definitions */
/* EAP-Type */
-int eap_module_load(rlm_eap_t *inst, eap_module_t **method, eap_type_t num,
- CONF_SECTION *cs);
+int eap_module_load(rlm_eap_t *inst, eap_module_t **method, eap_type_t num, CONF_SECTION *cs);
eap_rcode_t eap_method_select(rlm_eap_t *inst, eap_handler_t *handler);
/* EAP */
-int eap_start(rlm_eap_t *inst, REQUEST *request);
-void eap_fail(eap_handler_t *handler);
-void eap_success(eap_handler_t *handler);
-rlm_rcode_t eap_compose(eap_handler_t *handler);
-eap_handler_t *eap_handler(rlm_eap_t *inst, eap_packet_raw_t **eap_msg, REQUEST *request);
+int eap_start(rlm_eap_t *inst, REQUEST *request) CC_HINT(nonnull);
+void eap_fail(eap_handler_t *handler) CC_HINT(nonnull);
+void eap_success(eap_handler_t *handler) CC_HINT(nonnull);
+rlm_rcode_t eap_compose(eap_handler_t *handler) CC_HINT(nonnull);
+eap_handler_t *eap_handler(rlm_eap_t *inst, eap_packet_raw_t **eap_msg, REQUEST *request) CC_HINT(nonnull);
/* Memory Management */
EAP_DS *eap_ds_alloc(eap_handler_t *handler);
eap_handler_t *eap_handler_alloc(rlm_eap_t *inst);
void eap_ds_free(EAP_DS **eap_ds);
-int eaplist_add(rlm_eap_t *inst, eap_handler_t *handler);
-eap_handler_t *eaplist_find(rlm_eap_t *inst, REQUEST *request,
- eap_packet_raw_t *eap_packet);
+int eaplist_add(rlm_eap_t *inst, eap_handler_t *handler) CC_HINT(nonnull);
+eap_handler_t *eaplist_find(rlm_eap_t *inst, REQUEST *request, eap_packet_raw_t *eap_packet);
void eaplist_free(rlm_eap_t *inst);
/* State */
} rlm_eap_gtc_t;
static CONF_PARSER module_config[] = {
- { "challenge", PW_TYPE_STRING_PTR,
- offsetof(rlm_eap_gtc_t, challenge), NULL, "Password: " },
+ { "challenge", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_gtc_t, challenge), "Password: " },
- { "auth_type", PW_TYPE_STRING_PTR,
- offsetof(rlm_eap_gtc_t, auth_type_name), NULL, "PAP" },
+ { "auth_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_gtc_t, auth_type_name), "PAP" },
- { NULL, -1, 0, NULL, NULL } /* end the list */
+ { NULL, -1, 0, NULL, NULL } /* end the list */
};
return -1;
}
- dval = dict_valbyname(PW_AUTH_TYPE, 0, inst->auth_type_name);
- if (!dval) {
- ERROR("rlm_eap_gtc: Unknown Auth-Type %s",
- inst->auth_type_name);
- return -1;
- }
-
- inst->auth_type = dval->value;
+ if (inst->auth_type_name && *inst->auth_type_name) {
+ dval = dict_valbyname(PW_AUTH_TYPE, 0, inst->auth_type_name);
+ if (!dval) {
+ ERROR("rlm_eap_gtc: Unknown Auth-Type %s",
+ inst->auth_type_name);
+ return -1;
+ }
+ inst->auth_type = dval->value;
+ } else {
+ inst->auth_type = PW_AUTHTYPE_LOCAL;
+ }
return 0;
}
/*
* Authenticate a previously sent challenge.
*/
-static int mod_authenticate(void *instance, eap_handler_t *handler)
+static int CC_HINT(nonnull) mod_authenticate(void *instance, eap_handler_t *handler)
{
VALUE_PAIR *vp;
EAP_DS *eap_ds = handler->eap_ds;
/*
* Get the Cleartext-Password for this user.
*/
- rad_assert(request != NULL);
rad_assert(handler->stage == AUTHENTICATE);
/*
*/
if (inst->auth_type == PW_AUTHTYPE_LOCAL) {
/*
- * For now, do clear-text password authentication.
+ * For now, do cleartext password authentication.
*/
vp = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
if (!vp) {
- REDEBUG2("Cleartext-Password is required for authentication.");
+ REDEBUG2("Cleartext-Password is required for authentication");
eap_ds->request->code = PW_EAP_FAILURE;
return 0;
}
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-eap-ikev2-include-dir=DIR
- Directory where the eap-ikev2 includes may be found
+ Directory where the eap-ikev2 includes may be found
--with-eap-ikev2-lib-dir=DIR
- Directory where the eap-ikev2 libraries may be found
+ Directory where the eap-ikev2 libraries may be found
--with-eap-ikev2-dir=DIR
- Base directory where eap-ikev2 is installed
+ Base directory where eap-ikev2 is installed
Some influential environment variables:
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
no)
as_fn_error $? "Need eap-ikev2-include-dir" "$LINENO" 5
;;
- yes)
+ yes)
;;
*)
- eap_ikev2_include_dir="$withval"
+ eap_ikev2_include_dir="$withval"
;;
esac
fi
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=EAPIKEv2/connector.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-leap-ikev2"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-leap-ikev2"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libeap-ikev2${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libeap-ikev2.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
no)
AC_MSG_ERROR(Need eap-ikev2-include-dir)
;;
- yes)
+ yes)
;;
*)
- eap_ikev2_include_dir="$withval"
+ eap_ikev2_include_dir="$withval"
;;
esac])
(strcmp(compat_mode_str, "cistron") == 0)) {
PAIR_LIST *entry;
VALUE_PAIR *vp;
- int compat_mode = false;
+ bool compat_mode = false;
if (strcmp(compat_mode_str, "cistron") == 0) {
compat_mode = true;
if ((vp->da->vendor!= 0) ||
(vp->da->attr < 0x100)) {
if (!compat_mode) {
- WDEBUG("[%s]:%d Changing '%s =' to '%s =='\n\tfor comparing RADIUS attribute in check item list for user %s",
+ WARN("[%s]:%d Changing '%s =' to '%s =='\n\tfor comparing RADIUS attribute in check item list for user %s",
filename, entry->lineno,
vp->da->name, vp->da->name,
entry->name);
* good warning message.
*/
if ((vp->da->vendor == 0) &&
- (vp->da->attr > 0xff) &&
- (vp->da->attr > 1000)) {
- WDEBUG("[%s]:%d Check item \"%s\"\n"
+ (vp->da->attr > 1000)) {
+ WARN("[%s]:%d Check item \"%s\"\n"
"\tfound in reply item list for user \"%s\".\n"
"\tThis attribute MUST go on the first line"
" with the other check items",
char *server_idtype=NULL;
CONF_PARSER module_config[] = {
- { "ca_file", PW_TYPE_STRING_PTR,
- offsetof(ikev2_ctx,trusted),NULL,NULL },
- { "private_key_file",PW_TYPE_STRING_PTR,
- offsetof(ikev2_ctx,pkfile),NULL,NULL },
- { "private_key_password",PW_TYPE_STRING_PTR,
- offsetof(ikev2_ctx,pkfile_pwd),NULL,NULL },
- { "certificate_file", PW_TYPE_STRING_PTR,
- offsetof(ikev2_ctx,certificate_file),NULL,NULL },
- { "crl_file", PW_TYPE_STRING_PTR,
- offsetof(ikev2_ctx,crl_file),NULL,NULL },
- { "id", PW_TYPE_STRING_PTR,
- offsetof(ikev2_ctx,id),NULL,NULL },
- { "fragment_size",PW_TYPE_INTEGER,
- offsetof(ikev2_ctx,max_fragment_size),NULL,IKEv2_DEFAULT_MAX_FRAGMENT_SIZE_STR},
- { "dh_counter_max", PW_TYPE_INTEGER,
- offsetof(ikev2_ctx,DHCounterMax),NULL,IKEv2_DEFAULT_dh_counter_max_STR},
- { "default_authtype",PW_TYPE_STRING_PTR,
- 0,&default_authtype,"both" },
- { "usersfile",PW_TYPE_FILE_INPUT,
- 0,&usersfilename,"${confdir}/users" },
- { "server_authtype",PW_TYPE_STRING_PTR,
- 0,&server_authtype,"secret" },
- { "idtype",PW_TYPE_STRING_PTR,
- 0,&server_idtype,IKEv2_DEFAULT_IDTYPE_STR},
- { "certreq",PW_TYPE_BOOLEAN,
- offsetof(ikev2_ctx,sendCertReq),NULL,"no"},
- { "fast_dh_exchange",PW_TYPE_BOOLEAN,
- offsetof(ikev2_ctx,enableFastDHEx),NULL,"no"},
- { "fast_timer_expire",PW_TYPE_INTEGER,
- offsetof(ikev2_ctx,fastExpire),NULL,"900"},
- { "enable_fast_reauth",PW_TYPE_BOOLEAN,
- offsetof(ikev2_ctx,enableFastReconnect),NULL,"yes"},
-
-
- { NULL, -1, 0, NULL, NULL } /* end the list */
+ { "ca_file", FR_CONF_OFFSET(PW_TYPE_STRING, ikev2_ctx, trusted), NULL },
+ { "private_key_file", FR_CONF_OFFSET(PW_TYPE_STRING, ikev2_ctx, pkfile), NULL },
+ { "private_key_password", FR_CONF_OFFSET(PW_TYPE_STRING, ikev2_ctx, pkfile_pwd), NULL },
+ { "certificate_file", FR_CONF_OFFSET(PW_TYPE_STRING, ikev2_ctx, certificate_file), NULL },
+ { "crl_file", FR_CONF_OFFSET(PW_TYPE_STRING, ikev2_ctx, crl_file), NULL },
+ { "id", FR_CONF_OFFSET(PW_TYPE_STRING, ikev2_ctx, id), NULL },
+ { "fragment_size", FR_CONF_OFFSET(PW_TYPE_INTEGER, ikev2_ctx, max_fragment_size), IKEv2_DEFAULT_MAX_FRAGMENT_SIZE_STR },
+ { "dh_counter_max", FR_CONF_OFFSET(PW_TYPE_INTEGER, ikev2_ctx, DHCounterMax), IKEv2_DEFAULT_dh_counter_max_STR },
+ { "default_authtype", FR_CONF_POINTER(PW_TYPE_STRING, &default_authtype), "both" },
+ { "usersfile", FR_CONF_POINTER(PW_TYPE_FILE_INPUT, &usersfilename),"${confdir}/users" },
+ { "server_authtype", FR_CONF_POINTER(PW_TYPE_STRING, &server_authtype), "secret" },
+ { "idtype", FR_CONF_POINTER(PW_TYPE_STRING, &server_idtype), IKEv2_DEFAULT_IDTYPE_STR },
+ { "certreq", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, ikev2_ctx, sendCertReq), "no" },
+ { "fast_dh_exchange", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, ikev2_ctx, enableFastDHEx), "no" },
+ { "fast_timer_expire", FR_CONF_OFFSET(PW_TYPE_INTEGER, ikev2_ctx, fastExpire), "900" },
+ { "enable_fast_reauth", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, ikev2_ctx, enableFastReconnect), "yes" },
+
+
+ { NULL, -1, 0, NULL, NULL } /* end the list */
};
ikev2_set_log_callback(vxlogf);
{
INFO(IKEv2_LOG_PREFIX "Initiate connection!");
// This is the way for silent discarding behavior
-// handler->request->options|=RAD_REQUEST_OPTION_FAKE_REQUEST;
-// handler->request->options|=RAD_REQUEST_OPTION_DONT_CACHE;
+// handler->request->log.lvl|=RAD_REQUEST_OPTION_FAKE_REQUEST;
+// handler->request->log.lvl|=RAD_REQUEST_OPTION_DONT_CACHE;
// handler->request->reply->code=0;
// return 0;
session = FindSessionByFastid(i2, (char const *)eap_username);
if(!session) {
if(IKEv2BeginSession( i2, &session, IKEv2_STY_INITIATOR ) != IKEv2_RET_OK) {
- ERROR(IKEv2_LOG_PREFIX "Can't initialize IKEv2 session.");
+ ERROR(IKEv2_LOG_PREFIX "Can't initialize IKEv2 session");
return 1;
}
} else {
if(ComposeRadMsg(out,olen,handler->eap_ds)){
free(out);
return 0;
- }
+ }
free(out);
return 1;
}
leap_packet_t *eapleap_stage6(REQUEST *request, leap_packet_t *packet, VALUE_PAIR *user_name, VALUE_PAIR* password,
leap_session_t *session);
-void eapleap_lmpwdhash(unsigned char const *password,unsigned char *lmhash);
void eapleap_mschap(unsigned char const *win_password, unsigned char const *challenge, unsigned char *response);
#endif /*_EAP_LEAP_H*/
* len = header + type + leap_methoddata
* leap_methoddata = value_size + value
*/
-static int leap_initiate(UNUSED void *instance, eap_handler_t *handler)
+static int CC_HINT(nonnull) leap_initiate(UNUSED void *instance, eap_handler_t *handler)
{
REQUEST *request = handler->request;
leap_session_t *session;
return 1;
}
-static int mod_authenticate(UNUSED void *instance, eap_handler_t *handler)
+static int CC_HINT(nonnull) mod_authenticate(UNUSED void *instance, eap_handler_t *handler)
{
int rcode;
REQUEST *request = handler->request;
leap_packet_t *reply;
VALUE_PAIR *password;
- rad_assert(request);
-
if (!handler->opaque) {
REDEBUG("Cannot authenticate without LEAP history");
return 0;
* by eap_compose() in eap.c, when the EAP reply code
* is EAP_SUCCESS.
*/
- handler->request->reply->code = PW_ACCESS_CHALLENGE;
+ handler->request->reply->code = PW_CODE_ACCESS_CHALLENGE;
talloc_free(packet);
return 1;
}
/*
- * Converts the password to uppercase, and creates the LM
- * password hash.
- */
-void eapleap_lmpwdhash(unsigned char const *password, unsigned char *lmhash)
-{
- int i;
- unsigned char p14[14];
- static unsigned char sp8[8] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
-
- memset(p14, 0, sizeof(p14));
- for (i = 0; i < 14 && password[i]; i++) {
- p14[i] = toupper((int) password[i]);
- }
-
- smbhash(lmhash, sp8, p14);
- smbhash(lmhash+8, sp8, p14+7);
-}
-
-/*
* Take the NT or LM password, and return the MSCHAP response
*
* The win_password MUST be exactly 16 bytes long.
{
int i;
MD5_PACKET *reply;
+ REQUEST *request = handler->request;
/*
* Allocate an EAP-MD5 packet.
for (i = 0; i < reply->value_size; i++) {
reply->value[i] = fr_rand();
}
- DEBUG2("rlm_eap_md5: Issuing Challenge");
+ RDEBUG2("Issuing MD5 Challenge");
/*
* Keep track of the challenge.
MD5_PACKET *packet;
MD5_PACKET *reply;
VALUE_PAIR *password;
+ REQUEST *request = handler->request;
/*
* Get the Cleartext-Password for this user.
password = pairfind(handler->request->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
if (!password) {
- DEBUG2("rlm_eap_md5: Cleartext-Password is required for EAP-MD5 authentication");
+ RDEBUG2("Cleartext-Password is required for EAP-MD5 authentication");
return 0;
}
} rlm_eap_mschapv2_t;
static CONF_PARSER module_config[] = {
- { "with_ntdomain_hack", PW_TYPE_BOOLEAN,
- offsetof(rlm_eap_mschapv2_t,with_ntdomain_hack), NULL, "no" },
+ { "with_ntdomain_hack", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_mschapv2_t, with_ntdomain_hack), "no" },
- { "send_error", PW_TYPE_BOOLEAN,
- offsetof(rlm_eap_mschapv2_t,send_error), NULL, "no" },
+ { "send_error", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_mschapv2_t, send_error), "no" },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
switch (reply->da->attr) {
case PW_MSCHAP_CHALLENGE:
/*
- * 0 1 2 3
+ * 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Code | Identifier | Length |
+ * | Code | Identifier | Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Type | OpCode | MS-CHAPv2-ID | MS-Length...
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | MS-Length | Value-Size | Challenge...
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Challenge...
+ * | Challenge...
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Name...
+ * | Name...
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
length = MSCHAPV2_HEADER_LEN + MSCHAPV2_CHALLENGE_LEN + strlen(handler->identity);
- eap_ds->request->type.data = talloc_array(eap_ds->request,
- uint8_t, length);
+ eap_ds->request->type.data = talloc_array(eap_ds->request, uint8_t, length);
/*
* Allocate room for the EAP-MS-CHAPv2 data.
*/
/*
* Copy the Challenge, success, or error over.
*/
- memcpy(ptr, reply->vp_strvalue, reply->length);
+ memcpy(ptr, reply->vp_octets, reply->length);
memcpy((ptr + reply->length), handler->identity, strlen(handler->identity));
break;
case PW_MSCHAP2_SUCCESS:
/*
- * 0 1 2 3
+ * 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Code | Identifier | Length |
+ * | Code | Identifier | Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Type | OpCode | MS-CHAPv2-ID | MS-Length...
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | MS-Length | Message...
+ * | MS-Length | Message...
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
DEBUG2("MSCHAP Success\n");
case PW_MSCHAP_ERROR:
DEBUG2("MSCHAP Failure\n");
length = 4 + reply->length - 1;
- eap_ds->request->type.data = talloc_array(eap_ds->request,
- uint8_t, length);
+ eap_ds->request->type.data = talloc_array(eap_ds->request, uint8_t, length);
/*
* Allocate room for the EAP-MS-CHAPv2 data.
* We're at the stage where we're challenging the user.
*/
data->code = PW_EAP_MSCHAPV2_CHALLENGE;
- memcpy(data->challenge, challenge->vp_strvalue, MSCHAPV2_CHALLENGE_LEN);
+ memcpy(data->challenge, challenge->vp_octets, MSCHAPV2_CHALLENGE_LEN);
data->mppe_keys = NULL;
data->reply = NULL;
* The EAP session doesn't have enough information to
* proxy the "inside EAP" protocol. Disable EAP proxying.
*/
- handler->request->options &= ~RAD_REQUEST_OPTION_PROXY_EAP;
+ handler->request->log.lvl &= ~RAD_REQUEST_OPTION_PROXY_EAP;
#endif
/*
*
* Called from rlm_eap.c, eap_postproxy().
*/
-static int mschap_postproxy(eap_handler_t *handler, UNUSED void *tunnel_data)
+static int CC_HINT(nonnull) mschap_postproxy(eap_handler_t *handler, UNUSED void *tunnel_data)
{
VALUE_PAIR *response = NULL;
mschapv2_opaque_t *data;
REQUEST *request = handler->request;
data = (mschapv2_opaque_t *) handler->opaque;
- rad_assert(data != NULL);
rad_assert(request != NULL);
RDEBUG2("Passing reply from proxy back into the tunnel %d.",
* There is only a limited number of possibilities.
*/
switch (request->reply->code) {
- case PW_AUTHENTICATION_ACK:
- RDEBUG2("Proxied authentication succeeded.");
+ case PW_CODE_AUTHENTICATION_ACK:
+ RDEBUG2("Proxied authentication succeeded");
/*
* Move the attribute, so it doesn't go into
* the reply.
*/
- pairfilter(data, &response,
- &request->reply->vps,
- PW_MSCHAP2_SUCCESS, VENDORPEC_MICROSOFT, TAG_ANY);
+ pairfilter(data, &response, &request->reply->vps, PW_MSCHAP2_SUCCESS, VENDORPEC_MICROSOFT, TAG_ANY);
break;
default:
- case PW_AUTHENTICATION_REJECT:
- RDEBUG("Proxied authentication did not succeed.");
+ case PW_CODE_AUTHENTICATION_REJECT:
+ RDEBUG("Proxied authentication did not succeed");
return 0;
}
/*
* Done doing EAP proxy stuff.
*/
- request->options &= ~RAD_REQUEST_OPTION_PROXY_EAP;
+ request->log.lvl &= ~RAD_REQUEST_OPTION_PROXY_EAP;
eapmschapv2_compose(handler, response);
data->code = PW_EAP_MSCHAPV2_SUCCESS;
* And we need to challenge the user, not ack/reject them,
* so we re-write the ACK to a challenge. Yuck.
*/
- request->reply->code = PW_ACCESS_CHALLENGE;
+ request->reply->code = PW_CODE_ACCESS_CHALLENGE;
pairfree(&response);
return 1;
/*
* Authenticate a previously sent challenge.
*/
-static int mschapv2_authenticate(void *arg, eap_handler_t *handler)
+static int CC_HINT(nonnull) mschapv2_authenticate(void *arg, eap_handler_t *handler)
{
int rcode, ccode;
uint8_t *p;
+ size_t length;
+ char *q;
mschapv2_opaque_t *data;
EAP_DS *eap_ds = handler->eap_ds;
VALUE_PAIR *challenge, *response, *name;
rlm_eap_mschapv2_t *inst = (rlm_eap_mschapv2_t *) arg;
REQUEST *request = handler->request;
- rad_assert(request != NULL);
rad_assert(handler->stage == AUTHENTICATE);
data = (mschapv2_opaque_t *) handler->opaque;
}
failure:
- request->options &= ~RAD_REQUEST_OPTION_PROXY_EAP;
+ request->log.lvl &= ~RAD_REQUEST_OPTION_PROXY_EAP;
eap_ds->request->code = PW_EAP_FAILURE;
return 1;
/*
* It's a success. Don't proxy it.
*/
- request->options &= ~RAD_REQUEST_OPTION_PROXY_EAP;
+ request->log.lvl &= ~RAD_REQUEST_OPTION_PROXY_EAP;
#endif
pairfilter(request->reply,
&request->reply->vps,
* The MS-Length field is 5 + value_size + length
* of name, which is put after the response.
*/
- if (((eap_ds->response->type.data[2] << 8) |
- eap_ds->response->type.data[3]) < (5 + 49)) {
- REDEBUG("Response contains contradictory length %d %d",
- (eap_ds->response->type.data[2] << 8) |
- eap_ds->response->type.data[3], 5 + 49);
+ length = (eap_ds->response->type.data[2] << 8) | eap_ds->response->type.data[3];
+ if ((length < (5 + 49)) || (length > (256 + 5 + 49))) {
+ REDEBUG("Response contains contradictory length %zu %d",
+ length, 5 + 49);
return 0;
}
if (!response) {
return 0;
}
-
response->length = MSCHAPV2_RESPONSE_LEN;
response->vp_octets = p = talloc_array(response, uint8_t, response->length);
p[0] = eap_ds->response->type.data[1];
p[1] = eap_ds->response->type.data[5 + MSCHAPV2_RESPONSE_LEN];
- memcpy(p + 2, &eap_ds->response->type.data[5],
- MSCHAPV2_RESPONSE_LEN - 2);
+ memcpy(p + 2, &eap_ds->response->type.data[5], MSCHAPV2_RESPONSE_LEN - 2);
name = pairmake_packet("MS-CHAP-User-Name", NULL, T_OP_EQ);
if (!name) {
/*
* MS-Length - MS-Value - 5.
*/
- name->length = (((eap_ds->response->type.data[2] << 8) |
- eap_ds->response->type.data[3]) -
- eap_ds->response->type.data[4] - 5);
- name->vp_octets = p = talloc_array(name, uint8_t, name->length + 1);
- memcpy(p,
+ name->length = length - 49 - 5;
+ name->vp_strvalue = q = talloc_array(name, char, name->length + 1);
+ memcpy(q,
&eap_ds->response->type.data[4 + MSCHAPV2_RESPONSE_LEN],
name->length);
- p[name->length] = '\0';
+ q[name->length] = '\0';
packet_ready:
* EAP attributes, and proxy the MS-CHAP attributes to a
* home server.
*/
- if (request->options & RAD_REQUEST_OPTION_PROXY_EAP) {
+ if (request->log.lvl & RAD_REQUEST_OPTION_PROXY_EAP) {
char *username = NULL;
eap_tunnel_data_t *tunnel;
*/
response = NULL;
if (rcode == RLM_MODULE_OK) {
- pairfilter(data, &response, &request->reply->vps,
- PW_MSCHAP2_SUCCESS, VENDORPEC_MICROSOFT, TAG_ANY);
+ pairfilter(data, &response, &request->reply->vps, PW_MSCHAP2_SUCCESS, VENDORPEC_MICROSOFT, TAG_ANY);
data->code = PW_EAP_MSCHAPV2_SUCCESS;
-
} else if (inst->send_error) {
- pairfilter(data, &response, &request->reply->vps,
- PW_MSCHAP_ERROR, VENDORPEC_MICROSOFT, TAG_ANY);
+ pairfilter(data, &response, &request->reply->vps, PW_MSCHAP_ERROR, VENDORPEC_MICROSOFT, TAG_ANY);
if (response) {
int n,err,retry;
char buf[34];
+ VERIFY_VP(response);
+
RDEBUG2("MSCHAP-Error: %s", response->vp_strvalue);
/*
* No response, die.
*/
if (!response) {
- REDEBUG("No MS-CHAP-Success or MS-CHAP-Error was found.");
+ REDEBUG("No MS-CHAP-Success or MS-CHAP-Error was found");
return 0;
}
/*
* Process the PEAP portion of an EAP-PEAP request.
*/
-rlm_rcode_t eappeap_process(eap_handler_t *handler, tls_session_t *tls_session);
+rlm_rcode_t eappeap_process(eap_handler_t *handler, tls_session_t *tls_session) CC_HINT(nonnull);
#endif /* _EAP_PEAP_H */
*/
case PW_EAP_RESPONSE:
if (eap_packet->data[0] == PW_EAP_TLV) {
- RDEBUG2("Received EAP-TLV response.");
+ RDEBUG2("Received EAP-TLV response");
return 1;
}
- RDEBUG2("Got something weird.");
+ RDEBUG2("Got something weird");
break;
memcpy(p + EAP_HEADER_LEN, data, total);
- paircursor(&cursor, &head);
- pairinsert(&cursor, vp);
+ fr_cursor_init(&cursor, &head);
+ fr_cursor_insert(&cursor, vp);
while (total < data_len) {
vp = paircreate(packet, PW_EAP_MESSAGE, 0);
if (!vp) {
total += vp->length;
- pairinsert(&cursor, vp);
+ fr_cursor_insert(&cursor, vp);
}
return head;
size_t i, total, start = EAP_HEADER_LEN;
total = 0;
- for (this = paircursor(&cursor, &vp); this; this = pairnext(&cursor)) {
+ for (this = fr_cursor_init(&cursor, &vp); this; this = fr_cursor_next(&cursor)) {
for (i = start; i < vp->length; i++) {
if ((total & 0x0f) == 0) {
fprintf(fr_log_fp, " PEAP tunnel data out %04x: ", (int) total);
#endif
/*
- * Send the EAP data, WITHOUT the header.
+ * Send the EAP data in the first attribute, WITHOUT the
+ * header.
*/
(tls_session->record_plus)(&tls_session->clean_in, vp->vp_octets + EAP_HEADER_LEN, vp->length - EAP_HEADER_LEN);
/*
- * Send the rest of the EAP data.
+ * Send the rest of the EAP data, but skipping the first VP.
*/
- for (this = paircursor(&cursor, &vp);
+ fr_cursor_init(&cursor, &vp);
+ for (this = fr_cursor_next(&cursor);
this;
- this = pairnext(&cursor)) {
+ this = fr_cursor_next(&cursor)) {
(tls_session->record_plus)(&tls_session->clean_in, this->vp_octets, this->length);
}
}
if (data[10] == EAP_TLV_FAILURE) {
- RDEBUG2("Client rejected our response. The password is probably incorrect.");
+ RDEBUG2("Client rejected our response. The password is probably incorrect");
return 0;
}
}
/*
* Use a reply packet to determine what to do.
*/
-static int process_reply(eap_handler_t *handler, tls_session_t *tls_session,
- REQUEST *request, RADIUS_PACKET *reply)
+static int CC_HINT(nonnull) process_reply(eap_handler_t *handler, tls_session_t *tls_session,
+ REQUEST *request, RADIUS_PACKET *reply)
{
int rcode = RLM_MODULE_REJECT;
VALUE_PAIR *vp;
}
switch (reply->code) {
- case PW_AUTHENTICATION_ACK:
- RDEBUG2("Tunneled authentication was successful.");
+ case PW_CODE_AUTHENTICATION_ACK:
+ RDEBUG2("Tunneled authentication was successful");
t->status = PEAP_STATUS_SENT_TLV_SUCCESS;
eappeap_success(handler, tls_session);
rcode = RLM_MODULE_HANDLED;
}
break;
- case PW_AUTHENTICATION_REJECT:
- RDEBUG2("Tunneled authentication was rejected.");
+ case PW_CODE_AUTHENTICATION_REJECT:
+ RDEBUG2("Tunneled authentication was rejected");
t->status = PEAP_STATUS_SENT_TLV_FAILURE;
eappeap_failure(handler, tls_session);
rcode = RLM_MODULE_HANDLED;
break;
- case PW_ACCESS_CHALLENGE:
+ case PW_CODE_ACCESS_CHALLENGE:
RDEBUG2("Got tunneled Access-Challenge");
/*
/*
* Do post-proxy processing,
*/
-static int eappeap_postproxy(eap_handler_t *handler, void *data)
+static int CC_HINT(nonnull) eappeap_postproxy(eap_handler_t *handler, void *data)
{
int rcode;
tls_session_t *tls_session = (tls_session_t *) data;
REQUEST *fake, *request = handler->request;
- rad_assert(request != NULL);
- RDEBUG2("Passing reply from proxy back into the tunnel.");
+ RDEBUG2("Passing reply from proxy back into the tunnel");
/*
* If there was a fake request associated with the proxied
/*
* Do the callback, if it exists, and if it was a success.
*/
- if (fake && (handler->request->proxy_reply->code == PW_AUTHENTICATION_ACK)) {
+ if (fake && (handler->request->proxy_reply->code == PW_CODE_AUTHENTICATION_ACK)) {
peap_tunnel_t *t = tls_session->opaque;
t->home_access_accept = true;
* Perform a post-auth stage, which will get the EAP
* handler, too...
*/
- fake->options &= ~RAD_REQUEST_OPTION_PROXY_EAP;
+ fake->log.lvl &= ~RAD_REQUEST_OPTION_PROXY_EAP;
RDEBUG2("Passing reply back for EAP-MS-CHAP-V2");
process_post_proxy(0, fake);
request_free(&fake);
eaptls_fail(handler, 0);
return 0;
- break;
default: /* Don't Do Anything */
RDEBUG2("Got reply %d", request->proxy_reply->code);
return eaptls_success(handler, 0);
default:
- RDEBUG2("Reply was unknown.");
+ RDEBUG2("Reply was unknown");
break;
}
REQUEST *request = handler->request;
EAP_DS *eap_ds = handler->eap_ds;
- rad_assert(request != NULL);
-
/*
* Just look at the buffer directly, without doing
* record_minus. This lets us avoid another data copy.
if ((t->status != PEAP_STATUS_TUNNEL_ESTABLISHED) &&
!eapmessage_verify(request, data, data_len)) {
- RDEBUG2("FAILED processing PEAP: Tunneled data is invalid.");
+ RDEBUG2("FAILED processing PEAP: Tunneled data is invalid");
if (debug_flag > 2) print_tunneled_data(data, data_len);
return RLM_MODULE_REJECT;
}
case PEAP_STATUS_INNER_IDENTITY_REQ_SENT:
/* we're expecting an identity response */
if (data[0] != PW_EAP_IDENTITY) {
- RDEBUG("Expected EAP-Identity, got something else.");
+ RDEBUG("Expected EAP-Identity, got something else");
return RLM_MODULE_REJECT;
}
RDEBUG("Got SoH reply");
debug_pair_list(fake->reply->vps);
- if (fake->reply->code != PW_AUTHENTICATION_ACK) {
+ if (fake->reply->code != PW_CODE_AUTHENTICATION_ACK) {
RDEBUG2("SoH was rejected");
request_free(&fake);
t->status = PEAP_STATUS_SENT_TLV_FAILURE;
return RLM_MODULE_HANDLED;
}
- RDEBUG2("We sent a success, but received something weird in return.");
+ RDEBUG2("We sent a success, but the client did not agree");
return RLM_MODULE_REJECT;
/*
* packets after we told them to f*ck off.
*/
case PEAP_STATUS_SENT_TLV_FAILURE:
- RDEBUG(" The users session was previously rejected: returning reject (again.)");
- RDEBUG(" *** This means you need to read the PREVIOUS messages in the debug output");
- RDEBUG(" *** to find out the reason why the user was rejected.");
- RDEBUG(" *** Look for \"reject\" or \"fail\". Those earlier messages will tell you.");
- RDEBUG(" *** what went wrong, and how to fix the problem.");
+ RINDENT();
+ RDEBUG("The users session was previously rejected: returning reject (again.)");
+ RDEBUG("*** This means you need to read the PREVIOUS messages in the debug output");
+ RDEBUG("*** to find out the reason why the user was rejected");
+ RDEBUG("*** Look for \"reject\" or \"fail\". Those earlier messages will tell you");
+ RDEBUG("*** what went wrong, and how to fix the problem");
+ REXDENT();
+
return RLM_MODULE_REJECT;
case PEAP_STATUS_PHASE2_INIT:
pairadd(&fake->packet->vps, vp);
if (t->default_method != 0) {
- RDEBUG2("Setting default EAP type for tunneled EAP session.");
+ RDEBUG2("Setting default EAP type for tunneled EAP session");
vp = pairmake(fake, &fake->config_items, "EAP-Type", "0", T_OP_EQ);
vp->vp_integer = t->default_method;
}
* set it here.
*/
if (t->default_method != 0) {
- DEBUG2(" PEAP: Setting default EAP type for tunneled EAP session.");
+ DEBUG2(" PEAP: Setting default EAP type for tunneled EAP session");
vp = pairmake(fake, &fake->config_items, "EAP-Type", "0", T_OP_EQ);
vp->vp_integer = t->default_method;
}
* done, THEN we proxy it...
*/
if (!t->proxy_tunneled_request_as_eap) {
- fake->options |= RAD_REQUEST_OPTION_PROXY_EAP;
+ fake->log.lvl |= RAD_REQUEST_OPTION_PROXY_EAP;
/*
* Hmm... should we check for
/*
* Run the EAP authentication.
*/
- DEBUG2(" PEAP: Calling authenticate in order to initiate tunneled EAP session.");
+ DEBUG2(" PEAP: Calling authenticate in order to initiate tunneled EAP session");
rcode = process_authenticate(PW_AUTHTYPE_EAP, fake);
if (rcode == RLM_MODULE_OK) {
/*
* Authentication succeeded! Rah!
*/
- fake->reply->code = PW_AUTHENTICATION_ACK;
+ fake->reply->code = PW_CODE_AUTHENTICATION_ACK;
goto do_process;
}
* The module decided it wasn't
* done. Handle it like normal.
*/
- if ((fake->options & RAD_REQUEST_OPTION_PROXY_EAP) == 0) {
+ if ((fake->log.lvl & RAD_REQUEST_OPTION_PROXY_EAP) == 0) {
DEBUG2(" PEAP: Cancelling proxy to realm %s until the tunneled EAP session has been established", vp->vp_strvalue);
goto do_process;
}
* tunneled request.
*/
rad_assert(!request->proxy);
- request->proxy = fake->packet;
+ request->proxy = talloc_steal(request, fake->packet);
memset(&request->proxy->src_ipaddr, 0,
sizeof(request->proxy->src_ipaddr));
memset(&request->proxy->dst_ipaddr, 0,
* We're not proxying it as EAP, so we've got
* to do the callback later.
*/
- if ((fake->options & RAD_REQUEST_OPTION_PROXY_EAP) != 0) {
- DEBUG2(" PEAP: Remembering to do EAP-MS-CHAP-V2 post-proxy.");
+ if ((fake->log.lvl & RAD_REQUEST_OPTION_PROXY_EAP) != 0) {
+ DEBUG2(" PEAP: Remembering to do EAP-MS-CHAP-V2 post-proxy");
/*
* rlm_eap.c has taken care of associating
return rcode;
}
-static int setup_fake_request(REQUEST *request, REQUEST *fake, peap_tunnel_t *t) {
+static int CC_HINT(nonnull) setup_fake_request(REQUEST *request, REQUEST *fake, peap_tunnel_t *t) {
VALUE_PAIR *vp;
+
/*
* Tell the request that it's a fake one.
*/
VALUE_PAIR *copy;
vp_cursor_t cursor;
- for (vp = paircursor(&cursor, &request->packet->vps);
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
/*
* The attribute is a server-side thingy,
* don't copy it.
case PW_EAP_MESSAGE:
case PW_STATE:
continue;
- break;
/*
* By default, copy it over.
#include "eap_peap.h"
typedef struct rlm_eap_peap_t {
- /*
- * TLS configuration
- */
- char *tls_conf_name;
+ char const *tls_conf_name; //!< TLS configuration.
fr_tls_server_conf_t *tls_conf;
+ char const *default_method_name; //!< Default tunneled EAP type.
+ int default_method;
+ bool use_tunneled_reply; //!< Use the reply attributes from the tunneled session in
+ //!< the non-tunneled reply to the client.
- /*
- * Default tunneled EAP type
- */
- char *default_method_name;
- int default_method;
-
- /*
- * Use the reply attributes from the tunneled session in
- * the non-tunneled reply to the client.
- */
- bool use_tunneled_reply;
-
- /*
- * Use SOME of the request attributes from outside of the
- * tunneled session in the tunneled request
- */
- bool copy_request_to_tunnel;
-
+ bool copy_request_to_tunnel; //!< Use SOME of the request attributes from outside of the
+ //!< tunneled session in the tunneled request.
#ifdef WITH_PROXY
- /*
- * Proxy tunneled session as EAP, or as de-capsulated
- * protocol.
- */
- bool proxy_tunneled_request_as_eap;
+ bool proxy_tunneled_request_as_eap; //!< Proxy tunneled session as EAP, or as de-capsulated
+ //!< protocol.
#endif
+ char const *virtual_server; //!< Virtual server for inner tunnel session.
- /*
- * Virtual server for inner tunnel session.
- */
- char *virtual_server;
-
- /*
- * Do we do SoH request?
- */
- bool soh;
- char *soh_virtual_server;
-
- /*
- * Do we do require a client cert?
- */
- bool req_client_cert;
+ bool soh; //!< Do we do SoH request?
+ char const *soh_virtual_server;
+ bool req_client_cert; //!< Do we do require a client cert?
} rlm_eap_peap_t;
static CONF_PARSER module_config[] = {
- { "tls", PW_TYPE_STRING_PTR,
- offsetof(rlm_eap_peap_t, tls_conf_name), NULL, NULL },
+ { "tls", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_peap_t, tls_conf_name), NULL },
- { "default_method", PW_TYPE_STRING_PTR,
- offsetof(rlm_eap_peap_t, default_method_name), NULL, "mschapv2" },
+ { "default_method", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_peap_t, default_method_name), "mschapv2" },
- { "copy_request_to_tunnel", PW_TYPE_BOOLEAN,
- offsetof(rlm_eap_peap_t, copy_request_to_tunnel), NULL, "no" },
+ { "copy_request_to_tunnel", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_peap_t, copy_request_to_tunnel), "no" },
- { "use_tunneled_reply", PW_TYPE_BOOLEAN,
- offsetof(rlm_eap_peap_t, use_tunneled_reply), NULL, "no" },
+ { "use_tunneled_reply", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_peap_t, use_tunneled_reply), "no" },
#ifdef WITH_PROXY
- { "proxy_tunneled_request_as_eap", PW_TYPE_BOOLEAN,
- offsetof(rlm_eap_peap_t, proxy_tunneled_request_as_eap), NULL, "yes" },
+ { "proxy_tunneled_request_as_eap", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_peap_t, proxy_tunneled_request_as_eap), "yes" },
#endif
- { "virtual_server", PW_TYPE_STRING_PTR,
- offsetof(rlm_eap_peap_t, virtual_server), NULL, NULL },
+ { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_peap_t, virtual_server), NULL },
- { "soh", PW_TYPE_BOOLEAN,
- offsetof(rlm_eap_peap_t, soh), NULL, "no" },
+ { "soh", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_peap_t, soh), "no" },
- { "require_client_cert", PW_TYPE_BOOLEAN,
- offsetof(rlm_eap_peap_t, req_client_cert), NULL, "no" },
+ { "require_client_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_peap_t, req_client_cert), "no" },
- { "soh_virtual_server", PW_TYPE_STRING_PTR,
- offsetof(rlm_eap_peap_t, soh_virtual_server), NULL, NULL },
+ { "soh_virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_peap_t, soh_virtual_server), NULL },
- { NULL, -1, 0, NULL, NULL } /* end the list */
+ { NULL, -1, 0, NULL, NULL } /* end the list */
};
tls_session_t *ssn;
rlm_eap_peap_t *inst;
VALUE_PAIR *vp;
- int client_cert = false;
+ bool client_cert;
REQUEST *request = handler->request;
inst = type_arg;
/*
* Check if we need a client certificate.
*/
- client_cert = inst->req_client_cert;
/*
* EAP-TLS-Require-Client-Cert attribute will override
vp = pairfind(handler->request->config_items, PW_EAP_TLS_REQUIRE_CLIENT_CERT, 0, TAG_ANY);
if (vp) {
client_cert = vp->vp_integer;
+ } else {
+ client_cert = inst->req_client_cert;
}
ssn = eaptls_session(inst->tls_conf, handler, client_cert);
* Session is established, proceed with decoding
* tunneled data.
*/
- RDEBUG2("Session established. Decoding tunneled attributes.");
+ RDEBUG2("Session established. Decoding tunneled attributes");
/*
* We may need PEAP data associated with the session, so
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=openssl/ec.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$ac_cv_func_ev_group_free" != "xyes"; then
fail="EC_GROUP_free"
- fi
+ fi
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
)
if test "x$ac_cv_func_ev_group_free" != "xyes"; then
fail="EC_GROUP_free"
- fi
+ fi
fi
int
compute_password_element (pwd_session_t *sess, uint16_t grp_num,
char const *password, int password_len,
- char *id_server, int id_server_len,
- char *id_peer, int id_peer_len,
+ char const *id_server, int id_server_len,
+ char const *id_peer, int id_peer_len,
uint32_t *token)
{
BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL;
*/
H_Init(&ctx);
H_Update(&ctx, (uint8_t *)token, sizeof(*token));
- H_Update(&ctx, (uint8_t *)id_peer, id_peer_len);
- H_Update(&ctx, (uint8_t *)id_server, id_server_len);
+ H_Update(&ctx, (uint8_t const *)id_peer, id_peer_len);
+ H_Update(&ctx, (uint8_t const *)id_server, id_server_len);
H_Update(&ctx, (uint8_t const *)password, password_len);
H_Update(&ctx, (uint8_t *)&ctr, sizeof(ctr));
H_Final(&ctx, pwe_digest);
#define EAP_PWD_EXCH_CONFIRM 3
// uint16_t total_length; /* there if the L-bit is set */
uint8_t data[0];
-} __attribute__ ((packed)) pwd_hdr;
+} CC_HINT(packed) pwd_hdr;
#define EAP_PWD_GET_LENGTH_BIT(x) ((x)->lm_exchange & 0x80)
#define EAP_PWD_SET_LENGTH_BIT(x) ((x)->lm_exchange |= 0x80)
#define EAP_PWD_PREP_MS 1
#define EAP_PWD_PREP_SASL 2
char identity[0];
-} __attribute__ ((packed)) pwd_id_packet;
+} CC_HINT(packed) pwd_id_packet;
typedef struct _pwd_session_t {
uint16_t state;
int compute_password_element(pwd_session_t *sess, uint16_t grp_num,
char const *password, int password_len,
- char *id_server, int id_server_len,
- char *id_peer, int id_peer_len,
+ char const *id_server, int id_server_len,
+ char const *id_peer, int id_peer_len,
uint32_t *token);
int compute_scalar_element(pwd_session_t *sess, BN_CTX *bnctx);
int process_peer_commit (pwd_session_t *sess, uint8_t *commit, BN_CTX *bnctx);
#define MPPE_KEY_LEN 32
static CONF_PARSER pwd_module_config[] = {
- { "group", PW_TYPE_INTEGER,
- offsetof(EAP_PWD_CONF, group), NULL, "19"},
- { "fragment_size", PW_TYPE_INTEGER,
- offsetof(EAP_PWD_CONF, fragment_size), NULL, "1020"},
- { "server_id", PW_TYPE_STRING_PTR,
- offsetof(EAP_PWD_CONF, server_id), NULL, NULL },
- { "virtual_server", PW_TYPE_STRING_PTR,
- offsetof(EAP_PWD_CONF, virtual_server), NULL, NULL },
+ { "group", FR_CONF_OFFSET(PW_TYPE_INTEGER, EAP_PWD_CONF, group), "19" },
+ { "fragment_size", FR_CONF_OFFSET(PW_TYPE_INTEGER, EAP_PWD_CONF, fragment_size), "1020" },
+ { "server_id", FR_CONF_OFFSET(PW_TYPE_STRING, EAP_PWD_CONF, server_id), NULL },
+ { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, EAP_PWD_CONF, virtual_server), NULL },
{ NULL, -1, 0, NULL, NULL }
};
if (EAP_PWD_GET_MORE_BIT(hdr)) {
rad_assert(pwd_session->in_buf != NULL);
if ((pwd_session->in_buf_pos + len) > pwd_session->in_buf_len) {
- RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent.");
+ RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent");
return 0;
}
memcpy(pwd_session->in_buf + pwd_session->in_buf_pos, buf, len);
* the last fragment...
*/
if ((pwd_session->in_buf_pos + len) > pwd_session->in_buf_len) {
- RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent.");
+ RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent");
return 0;
}
memcpy(pwd_session->in_buf + pwd_session->in_buf_pos, buf, len);
#include <freeradius-devel/modules.h>
typedef struct eap_pwd_conf {
- int group;
- int fragment_size;
- char *server_id;
- char *virtual_server;
+ uint32_t group;
+ uint32_t fragment_size;
+ char const *server_id;
+ char const *virtual_server;
} EAP_PWD_CONF;
typedef struct _eap_pwd_t {
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
static int eap_sim_get_challenge(eap_handler_t *handler, VALUE_PAIR *vps, int idx, eap_sim_state_t *ess)
{
REQUEST *request = handler->request;
- VALUE_PAIR *vp;
+ VALUE_PAIR *vp, *ki, *algo_version;
rad_assert(idx >= 0 && idx < 3);
+ /*
+ * Generate a new RAND value, and derive Kc and SRES from Ki
+ */
+ ki = pairfind(vps, ATTRIBUTE_EAP_SIM_KI, 0, TAG_ANY);
+ if (ki) {
+ int i;
+
+ /*
+ * Check to see if have a Ki for the IMSI, this allows us to generate the rest
+ * of the triplets.
+ */
+ algo_version = pairfind(vps, ATTRIBUTE_EAP_SIM_ALGO_VERSION, 0, TAG_ANY);
+ if (!algo_version) {
+ REDEBUG("Found Ki, but missing EAP-Sim-Algo-Version");
+ return 0;
+ }
+
+ for (i = 0; i < EAPSIM_RAND_SIZE; i++) {
+ ess->keys.rand[idx][i] = fr_rand();
+ }
+
+ switch (algo_version->vp_integer) {
+ case 1:
+ comp128v1(ess->keys.sres[idx], ess->keys.Kc[idx], ki->vp_octets, ess->keys.rand[idx]);
+ break;
+
+ case 2:
+ comp128v23(ess->keys.sres[idx], ess->keys.Kc[idx], ki->vp_octets, ess->keys.rand[idx],
+ true);
+ break;
+
+ case 3:
+ comp128v23(ess->keys.sres[idx], ess->keys.Kc[idx], ki->vp_octets, ess->keys.rand[idx],
+ false);
+ break;
+
+ case 4:
+ REDEBUG("Comp128-4 algorithm is not supported as details have not yet been published. "
+ "If you have details of this algorithm please contact the FreeRADIUS "
+ "maintainers");
+ return 0;
+
+ default:
+ REDEBUG("Unknown/unsupported algorithm Comp128-%i", algo_version->vp_integer);
+ }
+
+ if (RDEBUG_ENABLED2) {
+ char buffer[33]; /* 32 hexits (16 bytes) + 1 */
+ char *p;
+
+ RDEBUG2("Generated following triplets for round %i:", idx);
+
+ p = buffer;
+ for (i = 0; i < EAPSIM_RAND_SIZE; i++) {
+ p += sprintf(p, "%02x", ess->keys.rand[idx][i]);
+ }
+ RDEBUG2("\tRAND : 0x%s", buffer);
+
+ p = buffer;
+ for (i = 0; i < EAPSIM_SRES_SIZE; i++) {
+ p += sprintf(p, "%02x", ess->keys.sres[idx][i]);
+ }
+ RDEBUG2("\tSRES : 0x%s", buffer);
+
+ p = buffer;
+ for (i = 0; i < EAPSIM_KC_SIZE; i++) {
+ p += sprintf(p, "%02x", ess->keys.Kc[idx][i]);
+ }
+ RDEBUG2("\tKc : 0x%s", buffer);
+ }
+ return 1;
+ }
+
+ /*
+ * Use known RAND, SRES, and Kc values, these may of been pulled in from an AuC,
+ * or created by sending challenges to the SIM directly.
+ */
vp = pairfind(vps, ATTRIBUTE_EAP_SIM_RAND1 + idx, 0, TAG_ANY);
- if(!vp) {
+ /* Hack for backwards compatibility */
+ if (!vp) {
+ vp = pairfind(request->reply->vps, ATTRIBUTE_EAP_SIM_KC1 + idx, 0, TAG_ANY);
+ }
+ if (!vp) {
/* bad, we can't find stuff! */
- REDEBUG("EAP-SIM Challenge[%i] not found", idx);
+ REDEBUG("EAP-SIM-RAND%i not found", idx + 1);
return 0;
}
- if(vp->length != EAPSIM_RAND_SIZE) {
- REDEBUG("EAP-SIM challenge[%i] is not 8 bytes, got %zu bytes", idx, vp->length);
+ if (vp->length != EAPSIM_RAND_SIZE) {
+ REDEBUG("EAP-SIM-RAND%i is not " STRINGIFY(EAPSIM_RAND_SIZE) " bytes, got %zu bytes",
+ idx + 1, vp->length);
return 0;
}
memcpy(ess->keys.rand[idx], vp->vp_strvalue, EAPSIM_RAND_SIZE);
vp = pairfind(vps, ATTRIBUTE_EAP_SIM_SRES1 + idx, 0, TAG_ANY);
+ /* Hack for backwards compatibility */
+ if (!vp) {
+ vp = pairfind(request->reply->vps, ATTRIBUTE_EAP_SIM_KC1 + idx, 0, TAG_ANY);
+ }
if (!vp) {
/* bad, we can't find stuff! */
- REDEBUG("EAP-SIM SRES[%i] not found", idx);
+ REDEBUG("EAP-SIM-SRES%i not found", idx + 1);
return 0;
}
if (vp->length != EAPSIM_SRES_SIZE) {
- REDEBUG("EAP-SIM SRES[%i] is not 16 bytes, got %zu bytes", idx, vp->length);
+ REDEBUG("EAP-SIM-SRES%i is not " STRINGIFY(EAPSIM_SRES_SIZE) " bytes, got %zu bytes",
+ idx + 1, vp->length);
return 0;
}
memcpy(ess->keys.sres[idx], vp->vp_strvalue, EAPSIM_SRES_SIZE);
vp = pairfind(vps, ATTRIBUTE_EAP_SIM_KC1 + idx, 0, TAG_ANY);
+ /* Hack for backwards compatibility */
+ if (!vp) {
+ vp = pairfind(request->reply->vps, ATTRIBUTE_EAP_SIM_KC1 + idx, 0, TAG_ANY);
+ }
if (!vp) {
/* bad, we can't find stuff! */
- REDEBUG("EAP-SIM Kc[%i] not found", idx);
+ REDEBUG("EAP-SIM-Kc%i not found", idx + 1);
return 0;
}
- if (vp->length != EAPSIM_Kc_SIZE) {
- REDEBUG("EAP-SIM Kc[%i] is not 16 bytes, got %zu bytes", idx, vp->length);
+ if (vp->length != EAPSIM_KC_SIZE) {
+ REDEBUG("EAP-SIM-Kc%i is not " STRINGIFY(EAPSIM_KC_SIZE) " bytes, got %zu bytes",
+ idx + 1, vp->length);
return 0;
}
- memcpy(ess->keys.Kc[idx], vp->vp_strvalue, EAPSIM_Kc_SIZE);
+ memcpy(ess->keys.Kc[idx], vp->vp_strvalue, EAPSIM_KC_SIZE);
return 1;
}
* Send the EAP Success message
*/
case eapsim_server_success:
- eap_sim_sendsuccess(handler);
+ eap_sim_sendsuccess(handler);
handler->eap_ds->request->code = PW_EAP_SUCCESS;
break;
/*
{
REQUEST *request = handler->request;
eap_sim_state_t *ess;
- VALUE_PAIR *vp;
- VALUE_PAIR *outvps;
time_t n;
- outvps = handler->request->reply->vps;
-
- vp = pairfind(outvps, ATTRIBUTE_EAP_SIM_RAND1, 0, TAG_ANY);
- if (!vp) {
- RDEBUG2("Can't initiate EAP-SIM, no RAND1 attribute");
- return 0;
- }
-
ess = talloc_zero(handler, eap_sim_state_t);
if (!ess) {
RDEBUG2("No space for EAP-SIM state");
/*
* Save the keying material, because it could change on a subsequent retrival.
*/
- if ((eap_sim_get_challenge(handler, outvps, 0, ess) +
- eap_sim_get_challenge(handler, outvps, 1, ess) +
- eap_sim_get_challenge(handler, outvps, 2, ess)) != 3) {
- RDEBUG2("Can't initiate EAP-SIM, missing attributes");
+ if (!eap_sim_get_challenge(handler, request->config_items, 0, ess) ||
+ !eap_sim_get_challenge(handler, request->config_items, 1, ess) ||
+ !eap_sim_get_challenge(handler, request->config_items, 2, ess)) {
return 0;
}
/*
* Record it for later keying
*/
- memcpy(ess->keys.versionselect, selectedversion_vp->vp_strvalue, sizeof(ess->keys.versionselect));
+ memcpy(ess->keys.versionselect, selectedversion_vp->vp_strvalue, sizeof(ess->keys.versionselect));
/*
* Double check the nonce size.
default:
rad_assert(0 == 1);
- }
+ }
return 0;
}
#endif
static CONF_PARSER module_config[] = {
- { "tls", PW_TYPE_STRING_PTR,
- offsetof(rlm_eap_tls_t, tls_conf_name), NULL, NULL },
+ { "tls", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_tls_t, tls_conf_name), NULL },
- { "virtual_server", PW_TYPE_STRING_PTR,
- offsetof(rlm_eap_tls_t, virtual_server), NULL, NULL },
+ { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_tls_t, virtual_server), NULL },
- { NULL, -1, 0, NULL, NULL } /* end the list */
+ { NULL, -1, 0, NULL, NULL } /* end the list */
};
/*
* Do authentication, by letting EAP-TLS do most of the work.
*/
-static int mod_authenticate(void *type_arg, eap_handler_t *handler)
+static int CC_HINT(nonnull) mod_authenticate(void *type_arg, eap_handler_t *handler)
{
fr_tls_status_t status;
tls_session_t *tls_session = (tls_session_t *) handler->opaque;
inst = type_arg;
- rad_assert(request != NULL);
-
RDEBUG2("Authenticate");
status = eaptls_process(handler);
&fake->reply->vps, 0, 0, TAG_ANY);
/* reject if virtual server didn't return accept */
- if (fake->reply->code != PW_AUTHENTICATION_ACK) {
+ if (fake->reply->code != PW_CODE_AUTHENTICATION_ACK) {
RDEBUG2("Certificates were rejected by the virtual server");
request_free(&fake);
eaptls_fail(handler, 0);
* data.
*/
case FR_TLS_OK:
- RDEBUG2("Received unexpected tunneled data after successful handshake.");
+ RDEBUG2("Received unexpected tunneled data after successful handshake");
#ifndef NDEBUG
if ((debug_flag > 2) && fr_log_fp) {
unsigned int i;
/*
* TLS configuration
*/
- char *tls_conf_name;
+ char const *tls_conf_name;
fr_tls_server_conf_t *tls_conf;
/*
* Virtual server for checking certificates
*/
- char *virtual_server;
+ char const *virtual_server;
} rlm_eap_tls_t;
#endif /* _RLM_EAP_TLS_H */
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-eap-tnc-include-dir=DIR
- Directory where the libtnc includes may be found
+ Directory where the libtnc includes may be found
--with-eap-tnc-lib-dir=DIR
- Directory where the libtnc libraries may be found
+ Directory where the libtnc libraries may be found
--with-eap-tnc-dir=DIR Base directory where libtnc is installed
Some influential environment variables:
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
no)
as_fn_error $? "Need eap-tnc-include-dir" "$LINENO" 5
;;
- yes)
+ yes)
;;
*)
- eap_tnc_include_dir="$withval"
+ eap_tnc_include_dir="$withval"
;;
esac
fi
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=naaeap/naaeap.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lnaaeap"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lnaaeap"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libnaaeap${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libnaaeap.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
no)
AC_MSG_ERROR(Need eap-tnc-include-dir)
;;
- yes)
+ yes)
;;
*)
- eap_tnc_include_dir="$withval"
+ eap_tnc_include_dir="$withval"
;;
esac])
#define SET_START(x) ((x) | (0x20))
typedef struct rlm_eap_tnc {
- char *connection_string;
+ char const *connection_string;
} rlm_eap_tnc_t;
static CONF_PARSER module_config[] = {
- { "connection_string", PW_TYPE_STRING_PTR,
- offsetof(rlm_eap_tnc_t, connection_string), NULL,
- "NAS Port: %{NAS-Port} NAS IP: %{NAS-IP-Address} NAS_PORT_TYPE: %{NAS-Port-Type}"},
+ { "connection_string", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_tnc_t, connection_string), "NAS Port: %{NAS-Port} NAS IP: %{NAS-IP-Address} NAS_PORT_TYPE: %{NAS-Port-Type}" },
- { NULL, -1, 0, NULL, NULL } /* end the list */
+ { NULL, -1, 0, NULL, NULL } /* end the list */
};
static int tnc_attach(CONF_SECTION *cs, void **instance)
/*
* Process the TTLS portion of an EAP-TTLS request.
*/
-int eapttls_process(eap_handler_t *handler, tls_session_t *tls_session);
+int eapttls_process(eap_handler_t *handler, tls_session_t *tls_session) CC_HINT(nonnull);
#endif /* _EAP_TTLS_H */
/*
* TLS configuration
*/
- char *tls_conf_name;
+ char const *tls_conf_name;
fr_tls_server_conf_t *tls_conf;
/*
* Default tunneled EAP type
*/
- char *default_method_name;
- int default_method;
+ char const *default_method_name;
+ int default_method;
/*
* Use the reply attributes from the tunneled session in
* the non-tunneled reply to the client.
*/
- bool use_tunneled_reply;
+ bool use_tunneled_reply;
/*
* Use SOME of the request attributes from outside of the
* tunneled session in the tunneled request
*/
- bool copy_request_to_tunnel;
+ bool copy_request_to_tunnel;
/*
* RFC 5281 (TTLS) says that the length field MUST NOT be
* RFC, we add the option here. If set to "no", it sends
* the length field in ONLY the first fragment.
*/
- bool include_length;
+ bool include_length;
/*
* Virtual server for inner tunnel session.
*/
- char *virtual_server;
+ char const *virtual_server;
/*
* Do we do require a client cert?
*/
- bool req_client_cert;
+ bool req_client_cert;
} rlm_eap_ttls_t;
static CONF_PARSER module_config[] = {
- { "tls", PW_TYPE_STRING_PTR,
- offsetof(rlm_eap_ttls_t, tls_conf_name), NULL, NULL },
-
- { "default_eap_type", PW_TYPE_STRING_PTR,
- offsetof(rlm_eap_ttls_t, default_method_name), NULL, "md5" },
-
- { "copy_request_to_tunnel", PW_TYPE_BOOLEAN,
- offsetof(rlm_eap_ttls_t, copy_request_to_tunnel), NULL, "no" },
-
- { "use_tunneled_reply", PW_TYPE_BOOLEAN,
- offsetof(rlm_eap_ttls_t, use_tunneled_reply), NULL, "no" },
-
- { "virtual_server", PW_TYPE_STRING_PTR,
- offsetof(rlm_eap_ttls_t, virtual_server), NULL, NULL },
-
- { "include_length", PW_TYPE_BOOLEAN,
- offsetof(rlm_eap_ttls_t, include_length), NULL, "yes" },
-
- { "require_client_cert", PW_TYPE_BOOLEAN,
- offsetof(rlm_eap_ttls_t, req_client_cert), NULL, "no" },
-
- { NULL, -1, 0, NULL, NULL } /* end the list */
+ { "tls", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ttls_t, tls_conf_name), NULL },
+ { "default_eap_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ttls_t, default_method_name), "md5" },
+ { "copy_request_to_tunnel", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, copy_request_to_tunnel), "no" },
+ { "use_tunneled_reply", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, use_tunneled_reply), "no" },
+ { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ttls_t, virtual_server), NULL },
+ { "include_length", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, include_length), "yes" },
+ { "require_client_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, req_client_cert), "no" },
+
+ { NULL, -1, 0, NULL, NULL } /* end the list */
};
tls_session_t *ssn;
rlm_eap_ttls_t *inst;
VALUE_PAIR *vp;
- int client_cert = false;
+ bool client_cert;
REQUEST *request = handler->request;
inst = type_arg;
/*
* Check if we need a client certificate.
*/
- client_cert = inst->req_client_cert;
/*
* EAP-TLS-Require-Client-Cert attribute will override
vp = pairfind(handler->request->config_items, PW_EAP_TLS_REQUIRE_CLIENT_CERT, 0, TAG_ANY);
if (vp) {
client_cert = vp->vp_integer;
+ } else {
+ client_cert = inst->req_client_cert;
}
ssn = eaptls_session(inst->tls_conf, handler, client_cert);
* Session is established, proceed with decoding
* tunneled data.
*/
- RDEBUG2("Session established. Proceeding to decode tunneled attributes.");
+ RDEBUG2("Session established. Proceeding to decode tunneled attributes");
/*
* We may need TTLS data associated with the session, so
*/
rcode = eapttls_process(handler, tls_session);
switch (rcode) {
- case PW_AUTHENTICATION_REJECT:
+ case PW_CODE_AUTHENTICATION_REJECT:
eaptls_fail(handler, 0);
return 0;
/*
* Access-Challenge, continue tunneled conversation.
*/
- case PW_ACCESS_CHALLENGE:
+ case PW_CODE_ACCESS_CHALLENGE:
eaptls_request(handler->eap_ds, tls_session);
return 1;
/*
* Success: Automatically return MPPE keys.
*/
- case PW_AUTHENTICATION_ACK:
+ case PW_CODE_AUTHENTICATION_ACK:
return eaptls_success(handler, 0);
/*
* that the request now has a "proxy" packet, and
* will proxy it, rather than returning an EAP packet.
*/
- case PW_STATUS_CLIENT:
+ case PW_CODE_STATUS_CLIENT:
#ifdef WITH_PROXY
rad_assert(handler->request->proxy != NULL);
#endif
#include "eap_chbind.h"
/*
- * 0 1 2 3
+ * 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | AVP Code |
+ * | AVP Code |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |V M r r r r r r| AVP Length |
+ * |V M r r r r r r| AVP Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Vendor-ID (opt) |
+ * | Vendor-ID (opt) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Data ...
* +-+-+-+-+-+-+-+-+
hdr_len = 12;
if (remaining < hdr_len) {
- RDEBUG2(" Diameter attribute is too small (%u) to contain a Diameter header", remaining);
+ RDEBUG2("Diameter attribute is too small (%u) to contain a Diameter header", remaining);
return 0;
}
if ((data[4] & 0x80) != 0) {
if (remaining < 16) {
- RDEBUG2(" Diameter attribute is too small to contain a Diameter header with Vendor-Id");
+ RDEBUG2("Diameter attribute is too small to contain a Diameter header with Vendor-Id");
return 0;
}
RADIUS_PACKET *packet = fake->packet; /* FIXME: api issues */
vp_cursor_t out;
- paircursor(&out, &first);
+ fr_cursor_init(&out, &first);
while (data_left > 0) {
rad_assert(data_left <= data_len);
goto do_octets;
}
- pairinsert(&out, vp);
+ fr_cursor_insert(&out, vp);
goto next_attr;
}
if (vp) pairfree(&vp);
da = dict_attrunknown(attr, vendor, true);
if (!da) return NULL;
- vp = pairalloc(NULL, da);
+ vp = pairalloc(packet, da);
+ if (!vp) return NULL;
pairmemcpy(vp, data, size);
break;
}
vp->vp_integer64 = ntohll(vp->vp_integer64);
break;
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
if (size != vp->length) {
RDEBUG2("Invalid length attribute %d",
attr);
vp->vp_signed = ntohl(vp->vp_signed);
break;
- case PW_TYPE_IPV6ADDR:
+ case PW_TYPE_IPV6_ADDR:
if (size != vp->length) goto raw;
memcpy(&vp->vp_ipv6addr, data, vp->length);
break;
- case PW_TYPE_IPV6PREFIX:
+ case PW_TYPE_IPV6_PREFIX:
if (size != vp->length) goto raw;
memcpy(&vp->vp_ipv6prefix, data, vp->length);
break;
/*
* Update the list.
*/
- pairinsert(&out, vp);
+ fr_cursor_insert(&out, vp);
next_attr:
/*
p = buffer;
total = 0;
- for (vp = paircursor(&cursor, &first); vp; vp = pairnext(&cursor)) {
+ for (vp = fr_cursor_init(&cursor, &first); vp; vp = fr_cursor_next(&cursor)) {
/*
* Too much data: die.
*/
length = 8;
break;
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
memcpy(p, &vp->vp_ipaddr, 4); /* network order */
length = 4;
break;
/*
* Use a reply packet to determine what to do.
*/
-static rlm_rcode_t process_reply(UNUSED eap_handler_t *handler, tls_session_t *tls_session,
- REQUEST *request, RADIUS_PACKET *reply)
+static rlm_rcode_t CC_HINT(nonnull) process_reply(UNUSED eap_handler_t *handler, tls_session_t *tls_session,
+ REQUEST *request, RADIUS_PACKET *reply)
{
rlm_rcode_t rcode = RLM_MODULE_REJECT;
VALUE_PAIR *vp;
ttls_tunnel_t *t = tls_session->opaque;
- rad_assert(request != NULL);
rad_assert(handler->request == request);
/*
* NOT 'eap start', so we should check for that....
*/
switch (reply->code) {
- case PW_AUTHENTICATION_ACK:
+ case PW_CODE_AUTHENTICATION_ACK:
RDEBUG("Got tunneled Access-Accept");
rcode = RLM_MODULE_OK;
vp = NULL;
pairfilter(tls_session, &vp, &reply->vps, PW_MSCHAP2_SUCCESS, VENDORPEC_MICROSOFT, TAG_ANY);
if (vp) {
- RDEBUG("Got MS-CHAP2-Success, tunneling it to the client in a challenge.");
+ RDEBUG("Got MS-CHAP2-Success, tunneling it to the client in a challenge");
rcode = RLM_MODULE_HANDLED;
t->authenticated = true;
break;
- case PW_AUTHENTICATION_REJECT:
+ case PW_CODE_AUTHENTICATION_REJECT:
RDEBUG("Got tunneled Access-Reject");
rcode = RLM_MODULE_REJECT;
break;
* an Access-Challenge means that we MUST tunnel
* a Reply-Message to the client.
*/
- case PW_ACCESS_CHALLENGE:
+ case PW_CODE_ACCESS_CHALLENGE:
RDEBUG("Got tunneled Access-Challenge");
/*
/*
* Do post-proxy processing,
*/
-static int eapttls_postproxy(eap_handler_t *handler, void *data)
+static int CC_HINT(nonnull) eapttls_postproxy(eap_handler_t *handler, void *data)
{
int rcode;
tls_session_t *tls_session = (tls_session_t *) data;
REQUEST *fake, *request = handler->request;
- rad_assert(request != NULL);
- RDEBUG("Passing reply from proxy back into the tunnel.");
+ RDEBUG("Passing reply from proxy back into the tunnel");
/*
* If there was a fake request associated with the proxied
/*
* Do the callback, if it exists, and if it was a success.
*/
- if (fake &&
- handler->request->proxy_reply &&
- (handler->request->proxy_reply->code == PW_AUTHENTICATION_ACK)) {
+ if (fake && (handler->request->proxy_reply->code == PW_CODE_AUTHENTICATION_ACK)) {
/*
* Terrible hacks.
*/
* Perform a post-auth stage for the tunneled
* session.
*/
- fake->options &= ~RAD_REQUEST_OPTION_PROXY_EAP;
+ fake->log.lvl &= ~RAD_REQUEST_OPTION_PROXY_EAP;
rcode = rad_postauth(fake);
RDEBUG2("post-auth returns %d", rcode);
/*
* Terrible hacks.
*/
- request->proxy = fake->packet;
+ request->proxy = talloc_steal(request, fake->packet);
fake->packet = NULL;
- request->proxy_reply = fake->reply;
+ request->proxy_reply = talloc_steal(request, fake->reply);
fake->reply = NULL;
/*
request_free(&fake);
eaptls_fail(handler, 0);
return 0;
- break;
default: /* Don't Do Anything */
RDEBUG2("Got reply %d",
/*
* Process the reply from the home server.
*/
- rcode = process_reply(handler, tls_session, handler->request,
- handler->request->proxy_reply);
+ rcode = process_reply(handler, tls_session, handler->request, handler->request->proxy_reply);
/*
* The proxy code uses the reply from the home server as
return eaptls_success(handler, 0);
default:
- RDEBUG("Reply was unknown.");
+ RDEBUG("Reply was unknown");
break;
}
*/
int eapttls_process(eap_handler_t *handler, tls_session_t *tls_session)
{
- int code = PW_AUTHENTICATION_REJECT;
+ int code = PW_CODE_AUTHENTICATION_REJECT;
rlm_rcode_t rcode;
REQUEST *fake;
VALUE_PAIR *vp;
eap_chbind_packet_t *chbind_packet;
size_t chbind_len;
- rad_assert(request != NULL);
-
/*
* Just look at the buffer directly, without doing
* record_minus.
*/
if (data_len == 0) {
if (t->authenticated) {
- RDEBUG("Got ACK, and the user was already authenticated.");
- return PW_AUTHENTICATION_ACK;
+ RDEBUG("Got ACK, and the user was already authenticated");
+ return PW_CODE_AUTHENTICATION_ACK;
} /* else no session, no data, die. */
/*
* wrong.
*/
RDEBUG2("SSL_read Error");
- return PW_AUTHENTICATION_REJECT;
+ return PW_CODE_AUTHENTICATION_REJECT;
}
#ifndef NDEBUG
#endif
if (!diameter_verify(request, data, data_len)) {
- return PW_AUTHENTICATION_REJECT;
+ return PW_CODE_AUTHENTICATION_REJECT;
}
/*
fake->packet->vps = diameter2vp(request, fake, tls_session->ssl, data, data_len);
if (!fake->packet->vps) {
request_free(&fake);
- return PW_AUTHENTICATION_REJECT;
+ return PW_CODE_AUTHENTICATION_REJECT;
}
/*
* set it here.
*/
if (t->default_method != 0) {
- RDEBUG("Setting default EAP type for tunneled EAP session.");
+ RDEBUG("Setting default EAP type for tunneled EAP session");
vp = paircreate(fake, PW_EAP_TYPE, 0);
rad_assert(vp != NULL);
vp->vp_integer = t->default_method;
* as it's permitted to do EAP without
* user-name.
*/
- RWDEBUG2("No EAP-Identity found to start EAP conversation.");
+ RWDEBUG2("No EAP-Identity found to start EAP conversation");
}
} /* else there WAS a t->username */
VALUE_PAIR *copy;
vp_cursor_t cursor;
- for (vp = paircursor(&cursor, &request->packet->vps); vp; vp = pairnext(&cursor)) {
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps); vp; vp = fr_cursor_next(&cursor)) {
/*
* The attribute is a server-side thingy,
* don't copy it.
/* clean up chbind req */
chbind_free(req);
- if (chbind_rcode != PW_AUTHENTICATION_ACK)
+ if (chbind_rcode != PW_CODE_AUTHENTICATION_ACK)
return chbind_rcode;
}
* Didn't authenticate the packet, but
* we're proxying it.
*/
- code = PW_STATUS_CLIENT;
+ code = PW_CODE_STATUS_CLIENT;
} else
#endif /* WITH_PROXY */
{
RDEBUG("No tunneled reply was found for request %d , and the request was not proxied: rejecting the user.",
request->number);
- code = PW_AUTHENTICATION_REJECT;
+ code = PW_CODE_AUTHENTICATION_REJECT;
}
break;
rcode = process_reply(handler, tls_session, request, fake->reply);
switch (rcode) {
case RLM_MODULE_REJECT:
- code = PW_AUTHENTICATION_REJECT;
+ code = PW_CODE_AUTHENTICATION_REJECT;
break;
case RLM_MODULE_HANDLED:
- code = PW_ACCESS_CHALLENGE;
+ code = PW_CODE_ACCESS_CHALLENGE;
break;
case RLM_MODULE_OK:
- code = PW_AUTHENTICATION_ACK;
+ code = PW_CODE_AUTHENTICATION_ACK;
break;
default:
- code = PW_AUTHENTICATION_REJECT;
+ code = PW_CODE_AUTHENTICATION_REJECT;
break;
}
break;
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
CPP C preprocessor
Use these variables to override the choices made by `configure' or to help
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lc"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lc"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libc${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libc.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
SMART_LIBS="$smart_lib $SMART_LIBS"
fi
- if test "x$ac_cv_lib_c_printf" != "xyes"; then
+ if test "x$ac_cv_lib_c_printf" != "xyes"; then
fail="$fail libc"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=stdio.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
--header=FILE[:TEMPLATE]
- instantiate the configuration header FILE
+ instantiate the configuration header FILE
Configuration files:
$config_files
dnl set $fail to what's missing, on fatal errors.
dnl use AC_MSG_WARN() on important messages.
FR_SMART_CHECK_LIB(c, printf)
- if test "x$ac_cv_lib_c_printf" != "xyes"; then
+ if test "x$ac_cv_lib_c_printf" != "xyes"; then
fail="$fail libc"
fi
*/
typedef struct rlm_example_t {
bool boolean;
- int value;
- char *string;
- uint32_t ipaddr;
+ uint32_t value;
+ char const *string;
+ fr_ipaddr_t ipaddr;
} rlm_example_t;
/*
* A mapping of configuration file names to internal variables.
*/
static const CONF_PARSER module_config[] = {
- { "integer", PW_TYPE_INTEGER, offsetof(rlm_example_t,value), NULL, "1" },
- { "boolean", PW_TYPE_BOOLEAN, offsetof(rlm_example_t,boolean), NULL, "no"},
- { "string", PW_TYPE_STRING_PTR, offsetof(rlm_example_t,string), NULL, NULL},
- { "ipaddr", PW_TYPE_IPADDR, offsetof(rlm_example_t,ipaddr), NULL, "*" },
+ { "integer", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_example_t, value), "1" },
+ { "boolean", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_example_t, boolean), "no" },
+ { "string", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_example_t, string), NULL },
+ { "ipaddr", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, rlm_example_t, ipaddr), "*" },
- { NULL, -1, 0, NULL, NULL } /* end the list */
+ { NULL, -1, 0, NULL, NULL } /* end the list */
};
* from the database. The authentication code only needs to check
* the password, the rest is done here.
*/
-static rlm_rcode_t mod_authorize(UNUSED void *instance, UNUSED REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, UNUSED REQUEST *request)
{
VALUE_PAIR *state;
*
* The server will take care of sending it to the user.
*/
- request->reply->code = PW_ACCESS_CHALLENGE;
- RDEBUG("Sending Access-Challenge.");
+ request->reply->code = PW_CODE_ACCESS_CHALLENGE;
+ RDEBUG("Sending Access-Challenge");
return RLM_MODULE_HANDLED;
}
/*
* Authenticate the user with the given password.
*/
-static rlm_rcode_t mod_authenticate(UNUSED void *instance, UNUSED REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(UNUSED void *instance, UNUSED REQUEST *request)
{
return RLM_MODULE_OK;
}
/*
* Massage the request before recording it or proxying it
*/
-static rlm_rcode_t mod_preacct(UNUSED void *instance, UNUSED REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_preacct(UNUSED void *instance, UNUSED REQUEST *request)
{
return RLM_MODULE_OK;
}
/*
* Write accounting information to this modules database.
*/
-static rlm_rcode_t mod_accounting(UNUSED void *instance, UNUSED REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(UNUSED void *instance, UNUSED REQUEST *request)
{
return RLM_MODULE_OK;
}
* max. number of logins, do a second pass and validate all
* logins by querying the terminal server (using eg. SNMP).
*/
-static rlm_rcode_t mod_checksimul(UNUSED void *instance, UNUSED REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_checksimul(UNUSED void *instance, UNUSED REQUEST *request)
{
request->simul_count=0;
char const *xlat_name;
int bare;
bool wait;
- char *program;
- char *input;
- char *output;
+ char const *program;
+ char const *input;
+ char const *output;
pair_lists_t input_list;
pair_lists_t output_list;
- char *packet_type;
+ char const *packet_type;
unsigned int packet_code;
bool shell_escape;
- int timeout;
+ uint32_t timeout;
} rlm_exec_t;
/*
* buffer over-flows.
*/
static const CONF_PARSER module_config[] = {
- { "wait", PW_TYPE_BOOLEAN, offsetof(rlm_exec_t,wait), NULL, "yes" },
- { "program", PW_TYPE_STRING_PTR, offsetof(rlm_exec_t,program), NULL, NULL },
- { "input_pairs", PW_TYPE_STRING_PTR, offsetof(rlm_exec_t,input), NULL, NULL },
- { "output_pairs", PW_TYPE_STRING_PTR, offsetof(rlm_exec_t,output), NULL, NULL },
- { "packet_type", PW_TYPE_STRING_PTR, offsetof(rlm_exec_t,packet_type), NULL, NULL },
- { "shell_escape", PW_TYPE_BOOLEAN, offsetof(rlm_exec_t,shell_escape), NULL, "yes" },
- { "timeout", PW_TYPE_INTEGER, offsetof(rlm_exec_t,timeout), NULL, NULL },
+ { "wait", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_exec_t, wait), "yes" },
+ { "program", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_exec_t, program), NULL },
+ { "input_pairs", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_exec_t, input), NULL },
+ { "output_pairs", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_exec_t, output), NULL },
+ { "packet_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_exec_t, packet_type), NULL },
+ { "shell_escape", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_exec_t, shell_escape), "yes" },
+ { "timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_exec_t, timeout), NULL },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
}
/*
- * FIXME: Do xlat of program name?
+ * This function does it's own xlat of the input program
+ * to execute.
*/
result = radius_exec_program(request, fmt, inst->wait, inst->shell_escape,
out, outlen, inst->timeout,
xlat_register(inst->xlat_name, exec_xlat, rlm_exec_shell_escape, inst);
- /*
- * Check whether program actually exists
- */
-
if (inst->input) {
p = inst->input;
inst->input_list = radius_list_name(&p, PAIR_LIST_UNKNOWN);
/*
* Dispatch an exec method
*/
-static rlm_rcode_t exec_dispatch(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_exec_dispatch(void *instance, REQUEST *request)
{
rlm_exec_t *inst = (rlm_exec_t *)instance;
rlm_rcode_t rcode;
/*
* This function does it's own xlat of the input program
* to execute.
- *
- * FIXME: if inst->program starts with %{, then
- * do an xlat ourselves. This will allow us to do
- * program = %{Exec-Program}, which this module
- * xlat's into it's string value, and then the
- * exec program function xlat's it's string value
- * into something else.
*/
status = radius_exec_program(request, inst->program, inst->wait, inst->shell_escape,
out, sizeof(out), inst->timeout,
- input_pairs ? *input_pairs : NULL, &answer);
+ inst->input ? *input_pairs : NULL,
+ inst->output ? &answer : NULL);
rcode = rlm_exec_status2rcode(request, out, strlen(out), status);
/*
*
* If we're not waiting, then there are no output pairs.
*/
- if (output_pairs) {
+ if (inst->output) {
pairmove(request, output_pairs, &answer);
}
pairfree(&answer);
*
* Then, call exec_dispatch.
*/
-static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
{
rlm_exec_t *inst = (rlm_exec_t *) instance;
rlm_rcode_t rcode;
return RLM_MODULE_NOOP;
}
- rcode = exec_dispatch(instance, request);
+ rcode = mod_exec_dispatch(instance, request);
goto finish;
}
case RLM_MODULE_FAIL:
case RLM_MODULE_INVALID:
case RLM_MODULE_REJECT:
- request->reply->code = PW_AUTHENTICATION_REJECT;
+ request->reply->code = PW_CODE_AUTHENTICATION_REJECT;
break;
default:
break;
*
* Then, call exec_dispatch.
*/
-static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
{
rlm_exec_t *inst = (rlm_exec_t *) instance;
int status;
* Exec-Program and Exec-Program-Wait.
*/
if (!inst->bare) {
- return exec_dispatch(instance, request);
+ return mod_exec_dispatch(instance, request);
}
vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM, 0, TAG_ANY);
module_t rlm_exec = {
RLM_MODULE_INIT,
"exec", /* Name */
- RLM_TYPE_CHECK_CONFIG_SAFE, /* type */
+ RLM_TYPE_THREAD_SAFE, /* type */
sizeof(rlm_exec_t),
module_config,
mod_instantiate, /* instantiation */
NULL, /* detach */
{
- exec_dispatch, /* authentication */
- exec_dispatch, /* authorization */
- exec_dispatch, /* pre-accounting */
+ mod_exec_dispatch, /* authentication */
+ mod_exec_dispatch, /* authorization */
+ mod_exec_dispatch, /* pre-accounting */
mod_accounting, /* accounting */
NULL, /* check simul */
- exec_dispatch, /* pre-proxy */
- exec_dispatch, /* post-proxy */
+ mod_exec_dispatch, /* pre-proxy */
+ mod_exec_dispatch, /* post-proxy */
mod_post_auth /* post-auth */
#ifdef WITH_COA
- , exec_dispatch,
- exec_dispatch
+ , mod_exec_dispatch,
+ mod_exec_dispatch
#endif
},
};
/*
* Check if account has expired, and if user may login now.
*/
-static rlm_rcode_t mod_authorize(UNUSED void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, REQUEST *request)
{
VALUE_PAIR *vp, *check_item = NULL;
*/
vp = pairfind(request->reply->vps, PW_SESSION_TIMEOUT, 0, TAG_ANY);
if (!vp) {
- vp = radius_paircreate(request, &request->reply->vps, PW_SESSION_TIMEOUT, 0);
+ vp = radius_paircreate(request->reply, &request->reply->vps, PW_SESSION_TIMEOUT, 0);
vp->vp_date = (uint32_t) (((time_t) check_item->vp_date) - request->timestamp);
} else if (vp->vp_date > ((uint32_t) (((time_t) check_item->vp_date) - request->timestamp))) {
vp->vp_date = (uint32_t) (((time_t) check_item->vp_date) - request->timestamp);
* @copyright 2002 Alan DeKok <aland@ox.org>
*/
RCSID("$Id$")
+USES_APPLE_DEPRECATED_API
#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/md5.h>
#include <freeradius-devel/base64.h>
#include <freeradius-devel/modules.h>
+#ifdef HAVE_OPENSSL_EVP_H
+# include <openssl/evp.h>
+#endif
+
#include <ctype.h>
#include "rlm_expr.h"
*/
typedef struct rlm_expr_t {
char const *xlat_name;
- char *allowed_chars;
+ char const *allowed_chars;
} rlm_expr_t;
static const CONF_PARSER module_config[] = {
- {"safe_characters", PW_TYPE_STRING_PTR,
- offsetof(rlm_expr_t, allowed_chars), NULL,
- "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"},
+ { "safe_characters", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_expr_t, allowed_chars), "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /" },
{NULL, -1, 0, NULL, NULL}
};
static char randstr_punc[] = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
static char randstr_salt[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmopqrstuvwxyz/.";
+/*
+ * Characters humans rarely confuse. Reduces char set considerably
+ * should only be used for things such as one time passwords.
+ */
+static char randstr_otp[] = "469ACGHJKLMNPQRUVWXYabdfhijkprstuvwxyz";
+
static int get_number(REQUEST *request, char const **string, int64_t *answer)
{
int i, found;
case TOKEN_DIVIDE:
if (x == 0) {
result = 0; /* we don't have NaN for integers */
- break;
+ } else {
+ result /= x;
}
- result /= x;
break;
case TOKEN_REMAINDER:
return strlen(out);
}
-/**
- * @brief Generate a random integer value
+/** Generate a random integer value
*
*/
static ssize_t rand_xlat(UNUSED void *instance, UNUSED REQUEST *request, char const *fmt,
return strlen(out);
}
-/**
- * @brief Generate a string of random chars
+/** Generate a string of random chars
*
* Build strings of random chars, useful for generating tokens and passcodes
* Format similar to String::Random.
while (*p && (--freespace > 0)) {
result = fr_rand();
switch (*p) {
- /*
- * Lowercase letters
- */
- case 'c':
- *out++ = 'a' + (result % 26);
- break;
+ /*
+ * Lowercase letters
+ */
+ case 'c':
+ *out++ = 'a' + (result % 26);
+ break;
- /*
- * Uppercase letters
- */
- case 'C':
- *out++ = 'A' + (result % 26);
- break;
+ /*
+ * Uppercase letters
+ */
+ case 'C':
+ *out++ = 'A' + (result % 26);
+ break;
- /*
- * Numbers
- */
- case 'n':
- *out++ = '0' + (result % 10);
- break;
+ /*
+ * Numbers
+ */
+ case 'n':
+ *out++ = '0' + (result % 10);
+ break;
- /*
- * Alpha numeric
- */
- case 'a':
- *out++ = randstr_salt[result % (sizeof(randstr_salt) - 3)];
- break;
+ /*
+ * Alpha numeric
+ */
+ case 'a':
+ *out++ = randstr_salt[result % (sizeof(randstr_salt) - 3)];
+ break;
- /*
- * Punctuation
- */
- case '!':
- *out++ = randstr_punc[result % (sizeof(randstr_punc) - 1)];
- break;
+ /*
+ * Punctuation
+ */
+ case '!':
+ *out++ = randstr_punc[result % (sizeof(randstr_punc) - 1)];
+ break;
- /*
- * Alpa numeric + punctuation
- */
- case '.':
- *out++ = '!' + (result % 95);
- break;
+ /*
+ * Alpa numeric + punctuation
+ */
+ case '.':
+ *out++ = '!' + (result % 95);
+ break;
- /*
- * Alpha numeric + salt chars './'
- */
- case 's':
- *out++ = randstr_salt[result % (sizeof(randstr_salt) - 1)];
+ /*
+ * Alpha numeric + salt chars './'
+ */
+ case 's':
+ *out++ = randstr_salt[result % (sizeof(randstr_salt) - 1)];
+ break;
+
+ /*
+ * Chars suitable for One Time Password tokens.
+ * Alpha numeric with easily confused char pairs removed.
+ */
+ case 'o':
+ *out++ = randstr_otp[result % (sizeof(randstr_otp) - 1)];
+ break;
+
+ /*
+ * Binary data as hexits (we don't really support
+ * non printable chars).
+ */
+ case 'h':
+ if (freespace < 2) {
break;
+ }
- /*
- * Binary data as hexits (we don't really support
- * non printable chars).
- */
- case 'h':
- if (freespace < 2) {
- break;
- }
+ snprintf(out, 3, "%02x", result % 256);
- snprintf(out, 3, "%02x", result % 256);
+ /* Already decremented */
+ freespace -= 1;
+ out += 2;
+ break;
- /* Already decremented */
- freespace -= 1;
- out += 2;
+ /*
+ * Binary data with uppercase hexits
+ */
+ case 'H':
+ if (freespace < 2) {
break;
+ }
- default:
- ERROR("rlm_expr: invalid character class '%c'", *p);
+ snprintf(out, 3, "%02X", result % 256);
- return -1;
+ /* Already decremented */
+ freespace -= 1;
+ out += 2;
+ break;
+
+ default:
+ ERROR("rlm_expr: invalid character class '%c'", *p);
+
+ return -1;
}
p++;
return outlen - freespace;
}
-/**
- * @brief URLencode special characters
+/** URLencode special characters
*
* Example: "%{urlquote:http://example.org/}" == "http%3A%47%47example.org%47"
*/
}
switch (*p) {
- case '-':
- case '_':
- case '.':
- case '~':
- *out++ = *p++;
+ case '-':
+ case '_':
+ case '.':
+ case '~':
+ *out++ = *p++;
+ break;
+ default:
+ if (freespace < 3)
break;
- default:
- if (freespace < 3)
- break;
- snprintf(out, 4, "%%%02x", *p++); /* %xx */
+ snprintf(out, 4, "%%%02x", *p++); /* %xx */
- /* Already decremented */
- freespace -= 2;
- out += 3;
+ /* Already decremented */
+ freespace -= 2;
+ out += 3;
}
}
return outlen - freespace;
}
-/**
- * @brief Equivalent to the old safe_characters functionality in rlm_sql
+/** Equivalent to the old safe_characters functionality in rlm_sql
*
* @verbatim Example: "%{escape:<img>foo.jpg</img>}" == "=60img=62foo.jpg=60/img=62" @endverbatim
*/
return outlen - freespace;
}
-/**
- * @brief Convert a string to lowercase
+/** Convert a string to lowercase
*
* Example "%{tolower:Bar}" == "bar"
*
return strlen(out);
}
-/**
- * @brief Convert a string to uppercase
+/** Convert a string to uppercase
*
* Example: "%{toupper:Foo}" == "FOO"
*
return strlen(out);
}
-/**
- * @brief Calculate the MD5 hash of a string.
+/** Calculate the MD5 hash of a string or attribute.
*
* Example: "%{md5:foo}" == "acbd18db4cc2f85cedef654fccc4a4d8"
*/
static ssize_t md5_xlat(UNUSED void *instance, UNUSED REQUEST *request,
- char const *fmt, char *out, size_t outlen)
+ char const *fmt, char *out, size_t outlen)
{
uint8_t digest[16];
- int i, len;
+ ssize_t i, len, inlen;
+ uint8_t const *p;
FR_MD5_CTX ctx;
/*
return 0;
}
+ inlen = xlat_fmt_to_ref(&p, request, fmt);
+ if (inlen < 0) {
+ return -1;
+ }
+
fr_MD5Init(&ctx);
- fr_MD5Update(&ctx, (const void *) fmt, strlen(fmt));
+ fr_MD5Update(&ctx, p, inlen);
fr_MD5Final(digest, &ctx);
/*
return strlen(out);
}
-/**
- * @brief Calculate the SHA1 hash of a string.
+/** Calculate the SHA1 hash of a string or attribute.
*
* Example: "%{sha1:foo}" == "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"
*/
static ssize_t sha1_xlat(UNUSED void *instance, UNUSED REQUEST *request,
- char const *fmt, char *out, size_t outlen)
+ char const *fmt, char *out, size_t outlen)
{
- uint8_t digest[20];
- int i, len;
- fr_SHA1_CTX ctx;
-
- /*
- * We need room for at least one octet of output.
- */
- if (outlen < 3) {
- *out = '\0';
- return 0;
- }
-
- fr_SHA1Init(&ctx);
- fr_SHA1Update(&ctx, (const void *) fmt, strlen(fmt));
- fr_SHA1Final(digest, &ctx);
-
- /*
- * Each digest octet takes two hex digits, plus one for
- * the terminating NUL. SHA1 is 160 bits (20 bytes)
- */
- len = (outlen / 2) - 1;
- if (len > 20) len = 20;
-
- for (i = 0; i < len; i++) {
- snprintf(out + i * 2, 3, "%02x", digest[i]);
- }
-
- return strlen(out);
+ uint8_t digest[20];
+ ssize_t i, len, inlen;
+ uint8_t const *p;
+ fr_SHA1_CTX ctx;
+
+ /*
+ * We need room for at least one octet of output.
+ */
+ if (outlen < 3) {
+ *out = '\0';
+ return 0;
+ }
+
+ inlen = xlat_fmt_to_ref(&p, request, fmt);
+ if (inlen < 0) {
+ return -1;
+ }
+
+ fr_SHA1Init(&ctx);
+ fr_SHA1Update(&ctx, p, inlen);
+ fr_SHA1Final(digest, &ctx);
+
+ /*
+ * Each digest octet takes two hex digits, plus one for
+ * the terminating NUL. SHA1 is 160 bits (20 bytes)
+ */
+ len = (outlen / 2) - 1;
+ if (len > 20) len = 20;
+
+ for (i = 0; i < len; i++) {
+ snprintf(out + i * 2, 3, "%02x", digest[i]);
+ }
+
+ return strlen(out);
}
-/**
- * @brief Encode string as base64
+/** Calculate any digest supported by OpenSSL EVP_MD
*
- * Example: "%{tobase64:foo}" == "Zm9v"
+ * Example: "%{sha256:foo}" == "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"
+ */
+#ifdef HAVE_OPENSSL_EVP_H
+static ssize_t evp_md_xlat(UNUSED void *instance, UNUSED REQUEST *request,
+ char const *fmt, char *out, size_t outlen, EVP_MD const *md)
+{
+ uint8_t digest[EVP_MAX_MD_SIZE];
+ unsigned int digestlen, i, len;
+ ssize_t inlen;
+ uint8_t const *p;
+
+ EVP_MD_CTX *ctx;
+
+ /*
+ * We need room for at least one octet of output.
+ */
+ if (outlen < 3) {
+ *out = '\0';
+ return 0;
+ }
+
+ inlen = xlat_fmt_to_ref(&p, request, fmt);
+ if (inlen < 0) {
+ return -1;
+ }
+
+ ctx = EVP_MD_CTX_create();
+ EVP_DigestInit_ex(ctx, md, NULL);
+ EVP_DigestUpdate(ctx, p, inlen);
+ EVP_DigestFinal_ex(ctx, digest, &digestlen);
+ EVP_MD_CTX_destroy(ctx);
+
+ /*
+ * Each digest octet takes two hex digits, plus one for
+ * the terminating NUL.
+ */
+ len = (outlen / 2) - 1;
+ if (len > digestlen) len = digestlen;
+
+ for (i = 0; i < len; i++) {
+ snprintf(out + i * 2, 3, "%02x", digest[i]);
+ }
+ return strlen(out);
+}
+
+# define EVP_MD_XLAT(_md) \
+static ssize_t _md##_xlat(UNUSED void *instance, UNUSED REQUEST *request, char const *fmt, char *out, size_t outlen)\
+{\
+ return evp_md_xlat(instance, request, fmt, out, outlen, EVP_##_md());\
+}
+
+EVP_MD_XLAT(sha256);
+EVP_MD_XLAT(sha512);
+#endif
+
+/** Encode string or attribute as base64
+ *
+ * Example: "%{base64:foo}" == "Zm9v"
*/
static ssize_t base64_xlat(UNUSED void *instance, UNUSED REQUEST *request,
char const *fmt, char *out, size_t outlen)
{
- ssize_t len;
+ ssize_t inlen;
+ uint8_t const *p;
- len = strlen(fmt);
+ inlen = xlat_fmt_to_ref(&p, request, fmt);
+ if (inlen < 0) {
+ return -1;
+ }
/*
* We can accurately calculate the length of the output string
* if it's larger than outlen, the output would be useless so abort.
*/
- if ((len < 0) || ((FR_BASE64_ENC_LENGTH(len) + 1) > (ssize_t) outlen)) {
- REDEBUG("xlat failed.");
+ if ((inlen < 0) || ((FR_BASE64_ENC_LENGTH(inlen) + 1) > (ssize_t) outlen)) {
+ REDEBUG("xlat failed");
*out = '\0';
return -1;
}
- return fr_base64_encode((const uint8_t *) fmt, len, out, outlen);
+ return fr_base64_encode(out, outlen, p, inlen);
}
-/**
- * @brief Convert base64 to hex
+/** Convert base64 to hex
*
* Example: "%{base64tohex:Zm9v}" == "666f6f"
*/
*out = '\0';
- declen = fr_base64_decode(fmt, len, decbuf, sizeof(decbuf));
+ declen = fr_base64_decode(decbuf, sizeof(decbuf), fmt, len);
if (declen < 0) {
REDEBUG("Base64 string invalid");
return -1;
if ((size_t)((declen * 2) + 1) > outlen) {
REDEBUG("Base64 conversion failed, output buffer exhausted, needed %zd bytes, have %zd bytes",
(declen * 2) + 1, outlen);
+ return -1;
}
return fr_bin2hex(out, decbuf, declen);
xlat_register("toupper", uc_xlat, NULL, inst);
xlat_register("md5", md5_xlat, NULL, inst);
xlat_register("sha1", sha1_xlat, NULL, inst);
- xlat_register("tobase64", base64_xlat, NULL, inst);
+#ifdef HAVE_OPENSSL_EVP_H
+ xlat_register("sha256", sha256_xlat, NULL, inst);
+ xlat_register("sha512", sha512_xlat, NULL, inst);
+#endif
+ xlat_register("base64", base64_xlat, NULL, inst);
xlat_register("base64tohex", base64_to_hex_xlat, NULL, inst);
/*
module_t rlm_expr = {
RLM_MODULE_INIT,
"expr", /* Name */
- RLM_TYPE_CHECK_CONFIG_SAFE, /* type */
+ 0, /* type */
sizeof(rlm_expr_t),
module_config,
mod_instantiate, /* instantiation */
#include <ctype.h>
#include <fcntl.h>
-#include <limits.h>
typedef struct rlm_files_t {
- char *compat_mode;
+ char const *compat_mode;
- char *key;
+ char const *key;
- char *filename;
+ char const *filename;
fr_hash_table_t *common;
/* autz */
- char *usersfile;
+ char const *usersfile;
fr_hash_table_t *users;
/* authenticate */
- char *auth_usersfile;
+ char const *auth_usersfile;
fr_hash_table_t *auth_users;
/* preacct */
- char *acctusersfile;
+ char const *acctusersfile;
fr_hash_table_t *acctusers;
#ifdef WITH_PROXY
/* pre-proxy */
- char *preproxy_usersfile;
+ char const *preproxy_usersfile;
fr_hash_table_t *preproxy_users;
/* post-proxy */
- char *postproxy_usersfile;
+ char const *postproxy_usersfile;
fr_hash_table_t *postproxy_users;
#endif
/* post-authenticate */
- char *postauth_usersfile;
+ char const *postauth_usersfile;
fr_hash_table_t *postauth_users;
} rlm_files_t;
}
static const CONF_PARSER module_config[] = {
- { "filename", PW_TYPE_FILE_INPUT,
- offsetof(rlm_files_t,filename), NULL, NULL },
- { "usersfile", PW_TYPE_FILE_INPUT,
- offsetof(rlm_files_t,usersfile), NULL, NULL },
- { "acctusersfile", PW_TYPE_FILE_INPUT,
- offsetof(rlm_files_t,acctusersfile), NULL, NULL },
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_files_t, filename), NULL },
+ { "usersfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_files_t, usersfile), NULL },
+ { "acctusersfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_files_t, acctusersfile), NULL },
#ifdef WITH_PROXY
- { "preproxy_usersfile", PW_TYPE_FILE_INPUT,
- offsetof(rlm_files_t,preproxy_usersfile), NULL, NULL },
- { "postproxy_usersfile", PW_TYPE_FILE_INPUT,
- offsetof(rlm_files_t,postproxy_usersfile), NULL, NULL },
+ { "preproxy_usersfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_files_t, preproxy_usersfile), NULL },
+ { "postproxy_usersfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_files_t, postproxy_usersfile), NULL },
#endif
- { "auth_usersfile", PW_TYPE_FILE_INPUT,
- offsetof(rlm_files_t,auth_usersfile), NULL, NULL },
- { "postauth_usersfile", PW_TYPE_FILE_INPUT,
- offsetof(rlm_files_t,postauth_usersfile), NULL, NULL },
- { "compat", PW_TYPE_STRING_PTR,
- offsetof(rlm_files_t,compat_mode), NULL, "cistron" },
- { "key", PW_TYPE_STRING_PTR,
- offsetof(rlm_files_t,key), NULL, NULL },
+ { "auth_usersfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_files_t, auth_usersfile), NULL },
+ { "postauth_usersfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_files_t, postauth_usersfile), NULL },
+ { "compat", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_files_t, compat_mode), "cistron" },
+ { "key", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_files_t, key), NULL },
{ NULL, -1, 0, NULL, NULL }
};
}
-static int getusersfile(TALLOC_CTX *ctx, char const *filename, fr_hash_table_t **pht,
- char *compat_mode_str)
+static int getusersfile(TALLOC_CTX *ctx, char const *filename, fr_hash_table_t **pht, char const *compat_mode_str)
{
int rcode;
PAIR_LIST *users = NULL;
if ((debug_flag) ||
(strcmp(compat_mode_str, "cistron") == 0)) {
VALUE_PAIR *vp;
- int compat_mode = false;
+ bool compat_mode = false;
if (strcmp(compat_mode_str, "cistron") == 0) {
compat_mode = true;
* and probably ':=' for server
* configuration items.
*/
- for (vp = paircursor(&cursor, &entry->check); vp; vp = pairnext(&cursor)) {
+ for (vp = fr_cursor_init(&cursor, &entry->check); vp; vp = fr_cursor_next(&cursor)) {
/*
* Ignore attributes which are set
* properly.
if ((vp->da->vendor != 0) ||
(vp->da->attr < 0x100)) {
if (!compat_mode) {
- WDEBUG("[%s]:%d Changing '%s =' to '%s =='\n\tfor comparing RADIUS attribute in check item list for user %s",
+ WARN("[%s]:%d Changing '%s =' to '%s =='\n\tfor comparing RADIUS attribute in check item list for user %s",
filename, entry->lineno,
vp->da->name, vp->da->name,
entry->name);
* It's a common enough mistake, that it's
* worth doing.
*/
- for (vp = paircursor(&cursor, &entry->reply); vp; vp = pairnext(&cursor)) {
+ for (vp = fr_cursor_init(&cursor, &entry->reply); vp; vp = fr_cursor_next(&cursor)) {
/*
* If it's NOT a vendor attribute,
* and it's NOT a wire protocol
* good warning message.
*/
if ((vp->da->vendor == 0) &&
- (vp->da->attr > 0xff) &&
(vp->da->attr > 1000)) {
- WDEBUG("[%s]:%d Check item \"%s\"\n"
+ WARN("[%s]:%d Check item \"%s\"\n"
"\tfound in reply item list for user \"%s\".\n"
"\tThis attribute MUST go on the first line"
" with the other check items", filename, entry->lineno, vp->da->name,
}
check_tmp = paircopy(request, pl->check);
- for (vp = paircursor(&cursor, &check_tmp);
+ for (vp = fr_cursor_init(&cursor, &check_tmp);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
if (radius_xlat_do(request, vp) < 0) {
RWARN("Failed parsing expanded value for check item, skipping entry: %s", fr_strerror());
pairfree(&check_tmp);
/* ctx may be reply or proxy */
reply_tmp = paircopy(request, pl->reply);
- radius_xlat_move(request, reply_pairs, &reply_tmp);
+ radius_pairmove(request, reply_pairs, reply_tmp, true);
pairmove(request, &request->config_items, &check_tmp);
-
- /* Cleanup any unmoved valuepairs */
- pairfree(&reply_tmp);
pairfree(&check_tmp);
/*
* for this user from the database. The main code only
* needs to check the password, the rest is done here.
*/
-static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
{
rlm_files_t *inst = instance;
* config_items. Reply items are Not Recommended(TM) in acct_users,
* except for Fallthrough, which should work
*/
-static rlm_rcode_t mod_preacct(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_preacct(void *instance, REQUEST *request)
{
rlm_files_t *inst = instance;
}
#ifdef WITH_PROXY
-static rlm_rcode_t file_preproxy(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_pre_proxy(void *instance, REQUEST *request)
{
rlm_files_t *inst = instance;
request->packet->vps, &request->proxy->vps);
}
-static rlm_rcode_t file_postproxy(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_post_proxy(void *instance, REQUEST *request)
{
rlm_files_t *inst = instance;
}
#endif
-static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
{
rlm_files_t *inst = instance;
request->packet->vps, &request->reply->vps);
}
-static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
{
rlm_files_t *inst = instance;
module_t rlm_files = {
RLM_MODULE_INIT,
"files",
- RLM_TYPE_CHECK_CONFIG_SAFE | RLM_TYPE_HUP_SAFE,
+ RLM_TYPE_HUP_SAFE,
sizeof(rlm_files_t),
module_config,
mod_instantiate, /* instantiation */
NULL, /* accounting */
NULL, /* checksimul */
#ifdef WITH_PROXY
- file_preproxy, /* pre-proxy */
- file_postproxy, /* post-proxy */
+ mod_pre_proxy, /* pre-proxy */
+ mod_post_proxy, /* post-proxy */
#else
NULL, NULL,
#endif
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
CPP C preprocessor
Use these variables to override the choices made by `configure' or to help
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lidn"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lidn"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libidn${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libidn.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
SMART_LIBS="$smart_lib $SMART_LIBS"
fi
- if test "x$ac_cv_lib_idn_idna_to_ascii_8z" != "xyes"; then
+ if test "x$ac_cv_lib_idn_idna_to_ascii_8z" != "xyes"; then
fail="$fail libidn"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=idna.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
AC_PROG_CPP
FR_SMART_CHECK_LIB(idn, idna_to_ascii_8z)
- if test "x$ac_cv_lib_idn_idna_to_ascii_8z" != "xyes"; then
+ if test "x$ac_cv_lib_idn_idna_to_ascii_8z" != "xyes"; then
fail="$fail libidn"
fi
* Structure for module configuration
*/
typedef struct rlm_idn_t {
- char const *xlat_name;
- bool use_std3_ascii_rules;
- bool allow_unassigned;
+ char const *xlat_name;
+ bool use_std3_ascii_rules;
+ bool allow_unassigned;
} rlm_idn_t;
/*
static const CONF_PARSER mod_config[] = {
/*
* If a STRINGPREP profile other than NAMEPREP is ever desired,
- * we can implement an option, and it will default to NAMEPREP settings.
- * ...and if we want raw punycode or to tweak Bootstring parameters,
- * we can do similar things. All defaults should result in IDNA
- * ToASCII with the use_std3_ascii_rules flag set, allow_unassigned unset,
- * because that is the forseeable use case.
- *
- * Note that doing anything much different will require choosing the
- * appropriate libidn API functions, as we currently call the IDNA
- * convenience functions.
- *
- * Also note that right now we do not provide ToUnicode, which may or
- * may not be useful as an xlat... depends on how the results need to
- * be used.
- */
-
- {"allow_unassigned", PW_TYPE_BOOLEAN, offsetof(rlm_idn_t, allow_unassigned), NULL, "no" },
- {"use_std3_ascii_rules", PW_TYPE_BOOLEAN, offsetof(rlm_idn_t, use_std3_ascii_rules), NULL, "yes" },
+ * we can implement an option, and it will default to NAMEPREP settings.
+ * ...and if we want raw punycode or to tweak Bootstring parameters,
+ * we can do similar things. All defaults should result in IDNA
+ * ToASCII with the use_std3_ascii_rules flag set, allow_unassigned unset,
+ * because that is the forseeable use case.
+ *
+ * Note that doing anything much different will require choosing the
+ * appropriate libidn API functions, as we currently call the IDNA
+ * convenience functions.
+ *
+ * Also note that right now we do not provide ToUnicode, which may or
+ * may not be useful as an xlat... depends on how the results need to
+ * be used.
+ */
+
+ { "allow_unassigned", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_idn_t, allow_unassigned), "no" },
+ { "use_std3_ascii_rules", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_idn_t, use_std3_ascii_rules), "yes" },
{ NULL, -1, 0, NULL, NULL }
};
char *idna = NULL;
int res;
size_t len;
- int flags = 0;
+ int flags = 0;
- if (inst->use_std3_ascii_rules) {
- flags |= IDNA_USE_STD3_ASCII_RULES;
- }
- if (inst->allow_unassigned) {
- flags |= IDNA_ALLOW_UNASSIGNED;
+ if (inst->use_std3_ascii_rules) {
+ flags |= IDNA_USE_STD3_ASCII_RULES;
+ }
+ if (inst->allow_unassigned) {
+ flags |= IDNA_ALLOW_UNASSIGNED;
}
- res = idna_to_ascii_8z(fmt, &idna, flags);
+ res = idna_to_ascii_8z(fmt, &idna, flags);
if (res) {
if (idna) {
free (idna); /* Docs unclear, be safe. */
return -1;
}
- len = strlen(idna);
+ len = strlen(idna);
/* 253 is max DNS length */
- if (!((len < (freespace - 1)) && (len <= 253))) {
- /* Never provide a truncated result, as it may be queried. */
+ if (!((len < (freespace - 1)) && (len <= 253))) {
+ /* Never provide a truncated result, as it may be queried. */
REDEBUG("Conversion was truncated");
free(idna);
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
CPP C preprocessor
Use these variables to override the choices made by `configure' or to help
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=gdbm.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lgdbm"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lgdbm"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libgdbm${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libgdbm.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
--header=FILE[:TEMPLATE]
- instantiate the configuration header FILE
+ instantiate the configuration header FILE
Configuration files:
$config_files
* be used as the instance handle.
*/
typedef struct rlm_ippool_t {
- char *filename;
- char *ip_index;
- char *name;
- char *key;
+ char const *filename;
+ char const *ip_index;
+ char const *name;
+ char const *key;
+
+ fr_ipaddr_t range_start_addr;
+ fr_ipaddr_t range_stop_addr;
+ fr_ipaddr_t netmask_addr;
uint32_t range_start;
uint32_t range_stop;
uint32_t netmask;
- time_t max_timeout;
- int cache_size;
+
+ uint32_t max_timeout;
+ uint32_t cache_size;
bool override;
GDBM_FILE gdbm;
GDBM_FILE ip;
} ippool_key;
static const CONF_PARSER module_config[] = {
- { "session-db", PW_TYPE_FILE_OUTPUT | PW_TYPE_DEPRECATED, offsetof(rlm_ippool_t,filename), NULL, NULL },
- { "filename", PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED, offsetof(rlm_ippool_t,filename), NULL, NULL },
+ { "session-db", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_DEPRECATED, rlm_ippool_t, filename), NULL },
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED, rlm_ippool_t, filename), NULL },
- { "ip-index", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_ippool_t,ip_index), NULL, NULL },
- { "ip_index", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED, offsetof(rlm_ippool_t,ip_index), NULL, NULL },
+ { "ip-index", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_ippool_t, ip_index), NULL },
+ { "ip_index", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_ippool_t, ip_index), NULL },
- { "key", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
- offsetof(rlm_ippool_t,key), NULL, "%{NAS-IP-Address} %{NAS-Port}" },
+ { "key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_ippool_t, key), "%{NAS-IP-Address} %{NAS-Port}" },
- { "range-start", PW_TYPE_IPADDR | PW_TYPE_DEPRECATED, offsetof(rlm_ippool_t,range_start), NULL, NULL },
- { "range_start", PW_TYPE_IPADDR, offsetof(rlm_ippool_t,range_start), NULL, "0" },
+ { "range-start", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR | PW_TYPE_DEPRECATED, rlm_ippool_t, range_start_addr), NULL },
+ { "range_start", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, rlm_ippool_t, range_start_addr), "0" },
- { "range-stop", PW_TYPE_IPADDR | PW_TYPE_DEPRECATED, offsetof(rlm_ippool_t,range_stop), NULL, NULL },
- { "range_stop", PW_TYPE_IPADDR, offsetof(rlm_ippool_t,range_stop), NULL, "0" },
+ { "range-stop", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR | PW_TYPE_DEPRECATED, rlm_ippool_t, range_stop_addr), NULL },
+ { "range_stop", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, rlm_ippool_t, range_stop_addr), "0" },
- { "netmask", PW_TYPE_IPADDR, offsetof(rlm_ippool_t,netmask), NULL, "0" },
+ { "netmask", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, rlm_ippool_t, netmask_addr), "0" },
- { "cache-size", PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, offsetof(rlm_ippool_t,cache_size), NULL, NULL },
- { "cache_size", PW_TYPE_INTEGER, offsetof(rlm_ippool_t,cache_size), NULL, "1000" },
+ { "cache-size", FR_CONF_OFFSET(PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, rlm_ippool_t, cache_size), NULL },
+ { "cache_size", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_ippool_t, cache_size), "1000" },
- { "override", PW_TYPE_BOOLEAN, offsetof(rlm_ippool_t,override), NULL, "no" },
+ { "override", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_ippool_t, override), "no" },
- { "maximum-timeout", PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, offsetof(rlm_ippool_t,max_timeout), NULL, NULL },
- { "maximum_timeout", PW_TYPE_INTEGER, offsetof(rlm_ippool_t,max_timeout), NULL, "0" },
+ { "maximum-timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, rlm_ippool_t, max_timeout), NULL },
+ { "maximum_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_ippool_t, max_timeout), "0" },
{ NULL, -1, 0, NULL, NULL }
};
*/
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
- rlm_ippool_t *inst = instance;
- int cache_size;
- ippool_info entry;
- ippool_key key;
- datum key_datum;
- datum data_datum;
- char const *cli = "0";
- char const *pool_name = NULL;
+ rlm_ippool_t *inst = instance;
+ int cache_size;
+ ippool_info entry;
+ ippool_key key;
+ datum key_datum;
+ datum data_datum;
+
+ char const *cli = "0";
+ char const *pool_name = NULL;
+
+ int rcode;
+ uint32_t i, j;
+ uint32_t or_result;
+ char str[32];
+ char init_str[17];
+
+ /*
+ * Add the ip pool name
+ */
+ inst->name = NULL;
+ pool_name = cf_section_name2(conf);
+ if (pool_name != NULL) {
+ inst->name = talloc_typed_strdup(inst, pool_name);
+ }
cache_size = inst->cache_size;
rad_assert(inst->filename && *inst->filename);
rad_assert(inst->ip_index && *inst->ip_index);
- inst->range_start = htonl(inst->range_start);
- inst->range_stop = htonl(inst->range_stop);
- inst->netmask = htonl(inst->netmask);
+ inst->range_start = htonl(*((uint32_t *)(&(inst->range_start_addr.ipaddr.ip4addr))));
+ inst->range_stop = htonl(*((uint32_t *)(&(inst->range_stop_addr.ipaddr.ip4addr))));
+ inst->netmask = htonl(*((uint32_t *)(&(inst->netmask_addr.ipaddr.ip4addr))));
if (inst->range_start == 0 || inst->range_stop == 0 || \
inst->range_start >= inst->range_stop ) {
cf_log_err_cs(conf, "Invalid data range");
return -1;
}
- inst->gdbm = gdbm_open(inst->filename, sizeof(int),
- GDBM_WRCREAT | GDBM_IPPOOL_OPTS, 0600, NULL);
+ {
+ char *file;
+
+ memcpy(&file, &inst->filename, sizeof(file));
+ inst->gdbm = gdbm_open(file, sizeof(int),
+ GDBM_WRCREAT | GDBM_IPPOOL_OPTS, 0600, NULL);
+ }
+
if (!inst->gdbm) {
- ERROR("rlm_ippool: Failed to open file %s: %s",
- inst->filename, strerror(errno));
+ ERROR("rlm_ippool: Failed to open file %s: %s", inst->filename, fr_syserror(errno));
+
return -1;
}
- inst->ip = gdbm_open(inst->ip_index, sizeof(int),
- GDBM_WRCREAT | GDBM_IPPOOL_OPTS, 0600, NULL);
+
+ {
+ char *file;
+
+ memcpy(&file, &inst->ip_index, sizeof(file));
+ inst->ip = gdbm_open(file, sizeof(int),
+ GDBM_WRCREAT | GDBM_IPPOOL_OPTS, 0600, NULL);
+ }
+
if (!inst->ip) {
- ERROR("rlm_ippool: Failed to open file %s: %s",
- inst->ip_index, strerror(errno));
+ ERROR("rlm_ippool: Failed to open file %s: %s", inst->ip_index, fr_syserror(errno));
+
return -1;
}
- if (gdbm_setopt(inst->gdbm, GDBM_CACHESIZE, &cache_size, sizeof(int)) == -1)
+
+ if (gdbm_setopt(inst->gdbm, GDBM_CACHESIZE, &cache_size, sizeof(int)) == -1) {
ERROR("rlm_ippool: Failed to set cache size");
- if (gdbm_setopt(inst->ip, GDBM_CACHESIZE, &cache_size, sizeof(int)) == -1)
+ }
+
+ if (gdbm_setopt(inst->ip, GDBM_CACHESIZE, &cache_size, sizeof(int)) == -1) {
ERROR("rlm_ippool: Failed to set cache size");
+ }
- key_datum = gdbm_firstkey(inst->gdbm);
- if (!key_datum.dptr){
- /*
- * If the database does not exist initialize it.
- * We set the nas/port pairs to not existent values and
- * active = 0
- */
- int rcode;
- uint32_t i, j;
- uint32_t or_result;
- char str[32];
- char init_str[17];
+ pthread_mutex_init(&inst->op_mutex, NULL);
- DEBUG("rlm_ippool: Initializing database");
- for(i=inst->range_start,j=~0;i<=inst->range_stop;i++,j--){
+ key_datum = gdbm_firstkey(inst->gdbm);
+ if (key_datum.dptr) {
+ free(key_datum.dptr);
+ return 0;
+ }
- /*
- * Net and Broadcast addresses are excluded
- */
- or_result = i | inst->netmask;
- if (~inst->netmask != 0 &&
- (or_result == inst->netmask ||
- (~or_result == 0))) {
- DEBUG("rlm_ippool: IP %s excluded",
- ip_ntoa(str, ntohl(i)));
- continue;
- }
+ /*
+ * If the database does not exist initialize it.
+ * We set the nas/port pairs to not existent values and
+ * active = 0
+ */
+ DEBUG("rlm_ippool: Initializing database");
+ for (i = inst->range_start, j=~0; i <= inst->range_stop; i++, j--){
+ /*
+ * Net and Broadcast addresses are excluded
+ */
+ or_result = i | inst->netmask;
+ if (~inst->netmask != 0 && (or_result == inst->netmask || (~or_result == 0))) {
+ DEBUG("rlm_ippool: IP %s excluded", ip_ntoa(str, ntohl(i)));
+ continue;
+ }
- sprintf(init_str,"%016d",j);
- DEBUG("rlm_ippool: Initialized bucket: %s",init_str);
- memcpy(key.key, init_str,16);
- key_datum.dptr = (char *) &key;
- key_datum.dsize = sizeof(ippool_key);
+ sprintf(init_str,"%016d",j);
+ DEBUG("rlm_ippool: Initialized bucket: %s",init_str);
+ memcpy(key.key, init_str,16);
+ key_datum.dptr = (char *) &key;
+ key_datum.dsize = sizeof(ippool_key);
- entry.ipaddr = ntohl(i);
- entry.active = 0;
- entry.extra = 0;
- entry.timestamp = 0;
- entry.timeout = 0;
- strcpy(entry.cli,cli);
+ entry.ipaddr = ntohl(i);
+ entry.active = 0;
+ entry.extra = 0;
+ entry.timestamp = 0;
+ entry.timeout = 0;
+ strcpy(entry.cli,cli);
- data_datum.dptr = (char *) &entry;
- data_datum.dsize = sizeof(ippool_info);
+ data_datum.dptr = (char *) &entry;
+ data_datum.dsize = sizeof(ippool_info);
- rcode = gdbm_store(inst->gdbm, key_datum, data_datum, GDBM_REPLACE);
- if (rcode < 0) {
- ERROR("rlm_ippool: Failed storing data to %s: %s",
- inst->filename, gdbm_strerror(gdbm_errno));
- gdbm_close(inst->gdbm);
- gdbm_close(inst->ip);
- return -1;
- }
+ rcode = gdbm_store(inst->gdbm, key_datum, data_datum, GDBM_REPLACE);
+ if (rcode < 0) {
+ ERROR("rlm_ippool: Failed storing data to %s: %s", inst->filename, gdbm_strerror(gdbm_errno));
+ gdbm_close(inst->gdbm);
+ gdbm_close(inst->ip);
+ return -1;
}
}
- else
- free(key_datum.dptr);
- /* Add the ip pool name */
- inst->name = NULL;
- pool_name = cf_section_name2(conf);
- if (pool_name != NULL)
- inst->name = strdup(pool_name);
+ return 0;
+}
- pthread_mutex_init(&inst->op_mutex, NULL);
+/** Decrease allocated count from the ip index
+ *
+ */
+static int decrease_allocated_count(rlm_ippool_t *inst, REQUEST *request, ippool_info *entry, datum *save_datum)
+{
+ datum data_datum;
+ datum key_datum;
+ int num;
+
+
+ key_datum.dptr = (char *) &(entry->ipaddr);
+ key_datum.dsize = sizeof(uint32_t);
+ data_datum = gdbm_fetch(inst->ip, key_datum);
+ if (!data_datum.dptr) {
+ return 0;
+ }
+ memcpy(&num, data_datum.dptr, sizeof(int));
+ free(data_datum.dptr);
+ if (num > 0){
+ int rcode;
+
+ num--;
+
+ RDEBUG("Allocated count now: %i", num);
+ data_datum.dptr = (char *) #
+ data_datum.dsize = sizeof(int);
+ rcode = gdbm_store(inst->ip, key_datum, data_datum, GDBM_REPLACE);
+ if (rcode < 0) {
+ RDEBUG("Failed storing data to %s: %s", inst->ip_index, gdbm_strerror(gdbm_errno));
+ return -1;
+ }
+ if ((num > 0) && entry->extra == 1){
+ /*
+ * We are doing MPPP and we still have nas/port entries referencing
+ * this ip. Delete this entry so that eventually we only keep one
+ * reference to this ip.
+ */
+ gdbm_delete(inst->gdbm, *save_datum);
+ }
+ }
return 0;
}
* Check for an Accounting-Stop
* If we find one and we have allocated an IP to this nas/port combination, deallocate it.
*/
-static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
{
- rlm_ippool_t *inst = instance;
- datum key_datum;
- datum data_datum;
- datum save_datum;
- int acctstatustype = 0;
- int rcode;
- ippool_info entry;
- ippool_key key;
- int num = 0;
- VALUE_PAIR *vp;
- char str[32];
- uint8_t key_str[17];
- char hex_str[35];
- char xlat_str[MAX_STRING_LEN];
- FR_MD5_CTX md5_context;
-
-
- if ((vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY)) != NULL)
- acctstatustype = vp->vp_integer;
- else {
- RDEBUG("Could not find account status type in packet. Return NOOP.");
- return RLM_MODULE_NOOP;
+ rlm_ippool_t *inst = instance;
+
+ datum key_datum;
+ ippool_key key;
+ datum data_datum;
+ ippool_info entry;
+ datum save_datum;
+
+ int rcode;
+ VALUE_PAIR *vp;
+
+ char str[32];
+ uint8_t key_str[17];
+ char hex_str[35];
+ char xlat_str[MAX_STRING_LEN];
+ int ret;
+
+ vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY);
+ if (!vp) {
+ RDEBUG2("Could not find account status type in packet");
+ return RLM_MODULE_INVALID;
}
- switch(acctstatustype){
- case PW_STATUS_STOP:
- if (radius_xlat(xlat_str, sizeof(xlat_str), request, inst->key, NULL, NULL) < 0){
- return RLM_MODULE_NOOP;
- }
- fr_MD5Init(&md5_context);
- fr_MD5Update(&md5_context, (uint8_t *)xlat_str,
- strlen(xlat_str));
- fr_MD5Final(key_str, &md5_context);
- key_str[16] = '\0';
- fr_bin2hex(hex_str, key_str, 16);
- hex_str[32] = '\0';
- RDEBUG("MD5 on 'key' directive maps to: %s",hex_str);
- memcpy(key.key,key_str,16);
- break;
- default:
- /* We don't care about any other accounting packet */
- RDEBUG("This is not an Accounting-Stop. Return NOOP.");
- return RLM_MODULE_NOOP;
+ switch (vp->vp_integer) {
+ case PW_STATUS_STOP:
+ {
+ FR_MD5_CTX md5_context;
+ if (radius_xlat(xlat_str, sizeof(xlat_str), request, inst->key, NULL, NULL) < 0){
+ return RLM_MODULE_FAIL;
+ }
+
+ fr_MD5Init(&md5_context);
+ fr_MD5Update(&md5_context, (uint8_t *)xlat_str, strlen(xlat_str));
+ fr_MD5Final(key_str, &md5_context);
+
+ key_str[16] = '\0';
+ fr_bin2hex(hex_str, key_str, 16);
+ hex_str[32] = '\0';
+
+ RDEBUG2("MD5 on 'key' directive maps to: %s", hex_str);
+ memcpy(key.key, key_str, 16);
+ break;
}
- RDEBUG("Searching for an entry for key: '%s'",xlat_str);
+ default:
+ /* We don't care about any other accounting packet */
+ RDEBUG2("This is not an Accounting-Stop");
+
+ return RLM_MODULE_NOOP;
+ }
+
+ RDEBUG2("Searching for an entry for key: '%s'", xlat_str);
key_datum.dptr = (char *) &key;
key_datum.dsize = sizeof(ippool_key);
pthread_mutex_lock(&inst->op_mutex);
data_datum = gdbm_fetch(inst->gdbm, key_datum);
- if (data_datum.dptr != NULL){
+ if (data_datum.dptr == NULL) {
+ pthread_mutex_unlock(&inst->op_mutex);
+ RDEBUG2("Entry not found");
- /*
- * If the entry was found set active to zero
- */
- memcpy(&entry, data_datum.dptr, sizeof(ippool_info));
- free(data_datum.dptr);
- RDEBUG("Deallocated entry for ip: %s",ip_ntoa(str,entry.ipaddr));
- entry.active = 0;
- entry.timestamp = 0;
- entry.timeout = 0;
+ return RLM_MODULE_NOTFOUND;
+ }
- /*
- * Save the reference to the entry
- */
- save_datum.dptr = key_datum.dptr;
- save_datum.dsize = key_datum.dsize;
+ /*
+ * If the entry was found set active to zero
+ */
+ memcpy(&entry, data_datum.dptr, sizeof(ippool_info));
+ free(data_datum.dptr);
- data_datum.dptr = (char *) &entry;
- data_datum.dsize = sizeof(ippool_info);
+ RDEBUG("Deallocated entry for ip: %s", ip_ntoa(str, entry.ipaddr));
+ entry.active = 0;
+ entry.timestamp = 0;
+ entry.timeout = 0;
- rcode = gdbm_store(inst->gdbm, key_datum, data_datum, GDBM_REPLACE);
- if (rcode < 0) {
- ERROR("rlm_ippool: Failed storing data to %s: %s",
- inst->filename, gdbm_strerror(gdbm_errno));
- pthread_mutex_unlock(&inst->op_mutex);
- return RLM_MODULE_FAIL;
- }
+ /*
+ * Save the reference to the entry
+ */
+ save_datum.dptr = key_datum.dptr;
+ save_datum.dsize = key_datum.dsize;
- /*
- * Decrease allocated count from the ip index
- */
- key_datum.dptr = (char *) &entry.ipaddr;
- key_datum.dsize = sizeof(uint32_t);
- data_datum = gdbm_fetch(inst->ip, key_datum);
- if (data_datum.dptr != NULL){
- memcpy(&num, data_datum.dptr, sizeof(int));
- free(data_datum.dptr);
- if (num >0){
- num--;
- RDEBUG("num: %d",num);
- data_datum.dptr = (char *) #
- data_datum.dsize = sizeof(int);
- rcode = gdbm_store(inst->ip, key_datum, data_datum, GDBM_REPLACE);
- if (rcode < 0) {
- ERROR("rlm_ippool: Failed storing data to %s: %s",
- inst->ip_index, gdbm_strerror(gdbm_errno));
- pthread_mutex_unlock(&inst->op_mutex);
- return RLM_MODULE_FAIL;
- }
- if (num >0 && entry.extra == 1){
- /*
- * We are doing MPPP and we still have nas/port entries referencing
- * this ip. Delete this entry so that eventually we only keep one
- * reference to this ip.
- */
- gdbm_delete(inst->gdbm,save_datum);
- }
- }
- }
+ data_datum.dptr = (char *) &entry;
+ data_datum.dsize = sizeof(ippool_info);
+ rcode = gdbm_store(inst->gdbm, key_datum, data_datum, GDBM_REPLACE);
+ if (rcode < 0) {
pthread_mutex_unlock(&inst->op_mutex);
+ REDEBUG("Failed storing data to %s: %s", inst->filename, gdbm_strerror(gdbm_errno));
+
+ return RLM_MODULE_FAIL;
}
- else{
- pthread_mutex_unlock(&inst->op_mutex);
- RDEBUG("Entry not found");
+
+ /*
+ * Decrease allocated count from the ip index
+ */
+ ret = decrease_allocated_count(inst, request, &entry, &save_datum);
+ pthread_mutex_unlock(&inst->op_mutex);
+ if (ret < 0) {
+ return RLM_MODULE_FAIL;
}
return RLM_MODULE_OK;
}
-static rlm_rcode_t mod_post_auth(UNUSED void *instance, UNUSED REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(UNUSED void *instance, UNUSED REQUEST *request)
{
rlm_ippool_t *inst = instance;
- int delete = 0;
- int found = 0;
- int mppp = 0;
- int extra = 0;
- int rcode;
- int num = 0;
- datum key_datum;
- datum nextkey;
- datum data_datum;
- datum save_datum;
- ippool_key key;
- ippool_info entry;
- VALUE_PAIR *vp;
- char const *cli = NULL;
- char str[32];
- uint8_t key_str[17];
- char hex_str[35];
- char xlat_str[MAX_STRING_LEN];
- FR_MD5_CTX md5_context;
+
+ datum key_datum;
+ ippool_key key;
+ datum nextkey;
+ datum data_datum;
+ ippool_info entry;
+ datum save_datum;
+
+ int delete = 0;
+ bool found = false;
+ int mppp = 0;
+ int extra = 0;
+ int rcode;
+ int num = 0;
+
+ VALUE_PAIR *vp;
+ char const *cli = NULL;
+ char str[32];
+ uint8_t key_str[17];
+ char hex_str[35];
+ char xlat_str[MAX_STRING_LEN];
+ FR_MD5_CTX md5_context;
+
#ifdef WITH_DHCP
- int dhcp = false;
+ bool dhcp = false;
#endif
- int attr_ipaddr = PW_FRAMED_IP_ADDRESS;
- int attr_ipmask = PW_FRAMED_IP_NETMASK;
- int vendor_ipaddr = 0;
+ int attr_ipaddr = PW_FRAMED_IP_ADDRESS;
+ int attr_ipmask = PW_FRAMED_IP_NETMASK;
+ int vendor_ipaddr = 0;
- /* Check if Pool-Name attribute exists. If it exists check our name and
- * run only if they match
+ /*
+ * Check if Pool-Name attribute exists. If it exists check our name and
+ * run only if they match
*/
- if ((vp = pairfind(request->config_items, PW_POOL_NAME, 0, TAG_ANY)) != NULL){
+ vp = pairfind(request->config_items, PW_POOL_NAME, 0, TAG_ANY);
+ if (vp != NULL){
if (!inst->name || (strcmp(inst->name,vp->vp_strvalue) && strcmp(vp->vp_strvalue,"DEFAULT")))
return RLM_MODULE_NOOP;
} else {
- RDEBUG("Could not find Pool-Name attribute.");
+ RDEBUG("Could not find Pool-Name attribute");
return RLM_MODULE_NOOP;
}
-
/*
- * Find the caller id
+ * Find the caller id
*/
- if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY)) != NULL)
+ vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY);
+ if (vp != NULL) {
cli = vp->vp_strvalue;
+ }
#ifdef WITH_DHCP
if (request->listener->type == RAD_LISTEN_DHCP) {
#endif
if (radius_xlat(xlat_str, sizeof(xlat_str), request, inst->key, NULL, NULL) < 0){
- return RLM_MODULE_NOOP;
+ return RLM_MODULE_FAIL;
}
fr_MD5Init(&md5_context);
key_str[16] = '\0';
fr_bin2hex(hex_str, key_str, 16);
hex_str[32] = '\0';
- RDEBUG("MD5 on 'key' directive maps to: %s",hex_str);
- memcpy(key.key,key_str,16);
- RDEBUG("Searching for an entry for key: '%s'",hex_str);
+ RDEBUG("MD5 on 'key' directive maps to: %s", hex_str);
+ memcpy(key.key, key_str, 16);
+
+ RDEBUG("Searching for an entry for key: '%s'", hex_str);
key_datum.dptr = (char *) &key;
key_datum.dsize = sizeof(ippool_key);
data_datum = gdbm_fetch(inst->gdbm, key_datum);
if (data_datum.dptr != NULL){
/*
- * If there is a corresponding entry in the database with active=1 it is stale.
- * Set active to zero
+ * If there is a corresponding entry in the database with active=1 it is stale.
+ * Set active to zero
*/
- found = 1;
+ found = true;
memcpy(&entry, data_datum.dptr, sizeof(ippool_info));
free(data_datum.dptr);
+
if (entry.active){
+ int ret;
RDEBUG("Found a stale entry for ip: %s",ip_ntoa(str,entry.ipaddr));
entry.active = 0;
entry.timestamp = 0;
entry.timeout = 0;
/*
- * Save the reference to the entry
+ * Save the reference to the entry
*/
save_datum.dptr = key_datum.dptr;
save_datum.dsize = key_datum.dsize;
rcode = gdbm_store(inst->gdbm, key_datum, data_datum, GDBM_REPLACE);
if (rcode < 0) {
- ERROR("rlm_ippool: Failed storing data to %s: %s",
- inst->filename, gdbm_strerror(gdbm_errno));
+ REDEBUG("Failed storing data to %s: %s", inst->filename, gdbm_strerror(gdbm_errno));
pthread_mutex_unlock(&inst->op_mutex);
return RLM_MODULE_FAIL;
}
- /* Decrease allocated count from the ip index */
- key_datum.dptr = (char *) &entry.ipaddr;
- key_datum.dsize = sizeof(uint32_t);
- data_datum = gdbm_fetch(inst->ip, key_datum);
- if (data_datum.dptr != NULL){
- memcpy(&num, data_datum.dptr, sizeof(int));
- free(data_datum.dptr);
- if (num >0){
- num--;
- RDEBUG("num: %d",num);
- data_datum.dptr = (char *) #
- data_datum.dsize = sizeof(int);
- rcode = gdbm_store(inst->ip, key_datum, data_datum, GDBM_REPLACE);
- if (rcode < 0) {
- ERROR("rlm_ippool: Failed storing data to %s: %s",
- inst->ip_index, gdbm_strerror(gdbm_errno));
- pthread_mutex_unlock(&inst->op_mutex);
- return RLM_MODULE_FAIL;
- }
- if (num >0 && entry.extra == 1){
- /*
- * We are doing MPPP and we still have nas/port entries referencing
- * this ip. Delete this entry so that eventually we only keep one
- * reference to this ip.
- */
- gdbm_delete(inst->gdbm,save_datum);
- }
- }
+ /*
+ * Decrease allocated count for the ip
+ */
+ ret = decrease_allocated_count(inst, request, &entry, &save_datum);
+ pthread_mutex_unlock(&inst->op_mutex);
+ if (ret < 0) {
+ return RLM_MODULE_FAIL;
}
}
}
pthread_mutex_unlock(&inst->op_mutex);
/*
- * If there is a Framed-IP-Address (or Dhcp-Your-IP-Address)
- * attribute in the reply, check for override
+ * If there is a Framed-IP-Address (or Dhcp-Your-IP-Address)
+ * attribute in the reply, check for override
*/
if (pairfind(request->reply->vps, attr_ipaddr, vendor_ipaddr, TAG_ANY) != NULL) {
- RDEBUG("Found IP address attribute in reply attribute list.");
- if (inst->override)
- {
- RDEBUG("Override supplied IP address");
- pairdelete(&request->reply->vps, attr_ipaddr, vendor_ipaddr, TAG_ANY);
- } else {
- /* Abort */
- RDEBUG("override is set to no. Return NOOP.");
+ RDEBUG("Found IP address attribute in reply attribute list");
+ if (!inst->override) {
+ RDEBUG("override is set to no. Return NOOP");
return RLM_MODULE_NOOP;
}
+
+ RDEBUG("Override supplied IP address");
+ pairdelete(&request->reply->vps, attr_ipaddr, vendor_ipaddr, TAG_ANY);
}
/*
- * Walk through the database searching for an active=0 entry.
- * We search twice. Once to see if we have an active entry with the same caller_id
- * so that MPPP can work ok and then once again to find a free entry.
+ * Walk through the database searching for an active=0 entry.
+ * We search twice. Once to see if we have an active entry with the same caller_id
+ * so that MPPP can work ok and then once again to find a free entry.
*/
-
pthread_mutex_lock(&inst->op_mutex);
-
key_datum.dptr = NULL;
if (cli != NULL){
key_datum = gdbm_firstkey(inst->gdbm);
- while(key_datum.dptr){
+ while (key_datum.dptr) {
data_datum = gdbm_fetch(inst->gdbm, key_datum);
if (data_datum.dptr){
memcpy(&entry,data_datum.dptr, sizeof(ippool_info));
free(data_datum.dptr);
/*
- * If we find an entry for the same caller-id with active=1
- * then we use that for multilink (MPPP) to work properly.
- */
+ * If we find an entry for the same caller-id with active=1
+ * then we use that for multilink (MPPP) to work properly.
+ */
if (strcmp(entry.cli,cli) == 0 && entry.active){
mppp = 1;
break;
}
}
+
nextkey = gdbm_nextkey(inst->gdbm, key_datum);
free(key_datum.dptr);
key_datum = nextkey;
rcode = gdbm_store(inst->gdbm, key_datum, data_datum_tmp, GDBM_REPLACE);
free(data_datum_tmp.dptr);
if (rcode < 0) {
- ERROR("rlm_ippool: Failed storing data to %s: %s",
- inst->filename, gdbm_strerror(gdbm_errno));
+ REDEBUG("Failed storing data to %s: %s", inst->filename, gdbm_strerror(gdbm_errno));
pthread_mutex_unlock(&inst->op_mutex);
return RLM_MODULE_FAIL;
}
}
- }
- else{
+ } else{
/*
* We have not found the nas/port combination
*/
- if (delete){
+ if (delete) {
/*
- * Delete the entry so that we can change the key
- * All is well. We delete one entry and we add one entry
- */
+ * Delete the entry so that we can change the key
+ * All is well. We delete one entry and we add one entry
+ */
gdbm_delete(inst->gdbm, key_datum);
- }
- else{
+ } else{
/*
- * We are doing MPPP. (mppp should be 1)
- * We don't do anything.
- * We will create an extra not needed entry in the database in this case
- * but we don't really care since we always also use the ip_index database
- * when we search for a free entry.
- * We will also delete that entry on the accounting section so that we only
- * have one nas/port entry referencing each ip
+ * We are doing MPPP. (mppp should be 1)
+ * We don't do anything.
+ * We will create an extra not needed entry in the database in this case
+ * but we don't really care since we always also use the ip_index database
+ * when we search for a free entry.
+ * We will also delete that entry on the accounting section so that we only
+ * have one nas/port entry referencing each ip
*/
- if (mppp)
+ if (mppp) {
extra = 1;
- if (!mppp)
- ERROR("rlm_ippool: mppp is not one. Please report this behaviour.");
+ }
+ if (!mppp) {
+ REDEBUG("mppp is not one. Please report this behaviour");
+ }
}
}
free(key_datum.dptr);
entry.timeout = (time_t) vp->vp_integer;
#ifdef WITH_DHCP
if (dhcp) {
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
PW_DHCP_IP_ADDRESS_LEASE_TIME, DHCP_MAGIC_VENDOR);
vp->vp_integer = entry.timeout;
pairdelete(&request->reply->vps, PW_SESSION_TIMEOUT, 0, TAG_ANY);
} else {
entry.timeout = 0;
}
- if (extra)
+ if (extra) {
entry.extra = 1;
+ }
+
data_datum.dptr = (char *) &entry;
data_datum.dsize = sizeof(ippool_info);
memcpy(key.key, key_str, 16);
key_datum.dptr = (char *) &key;
key_datum.dsize = sizeof(ippool_key);
- DEBUG2("rlm_ippool: Allocating ip to key: '%s'",hex_str);
+ RDEBUG2("Allocating ip to key: '%s'",hex_str);
rcode = gdbm_store(inst->gdbm, key_datum, data_datum, GDBM_REPLACE);
if (rcode < 0) {
- ERROR("rlm_ippool: Failed storing data to %s: %s",
- inst->filename, gdbm_strerror(gdbm_errno));
+ REDEBUG("Failed storing data to %s: %s", inst->filename, gdbm_strerror(gdbm_errno));
pthread_mutex_unlock(&inst->op_mutex);
return RLM_MODULE_FAIL;
}
if (data_datum.dptr){
memcpy(&num,data_datum.dptr,sizeof(int));
free(data_datum.dptr);
- } else
+ } else {
num = 0;
+ }
+
num++;
RDEBUG("num: %d",num);
data_datum.dptr = (char *) #
data_datum.dsize = sizeof(int);
rcode = gdbm_store(inst->ip, key_datum, data_datum, GDBM_REPLACE);
if (rcode < 0) {
- ERROR("rlm_ippool: Failed storing data to %s: %s",
- inst->ip_index, gdbm_strerror(gdbm_errno));
+ REDEBUG("Failed storing data to %s: %s", inst->ip_index, gdbm_strerror(gdbm_errno));
pthread_mutex_unlock(&inst->op_mutex);
return RLM_MODULE_FAIL;
}
pthread_mutex_unlock(&inst->op_mutex);
-
RDEBUG("Allocated ip %s to client key: %s",ip_ntoa(str,entry.ipaddr),hex_str);
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
attr_ipaddr, vendor_ipaddr);
vp->vp_ipaddr = entry.ipaddr;
* reply, add one
*/
if (pairfind(request->reply->vps, attr_ipmask, vendor_ipaddr, TAG_ANY) == NULL) {
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
attr_ipmask, vendor_ipaddr);
vp->vp_ipaddr = ntohl(inst->netmask);
}
}
else{
pthread_mutex_unlock(&inst->op_mutex);
- RDEBUG("No available ip addresses in pool.");
+ RDEBUG("No available ip addresses in pool");
return RLM_MODULE_NOTFOUND;
}
typedef struct old_ippool_key {
char nas[MAX_NAS_NAME_SIZE];
- unsigned int port;
+ uint16_t port;
} old_ippool_key;
typedef struct ippool_key {
void addip(char *sessiondbname, char *indexdbname, char *ipaddress,
char *NASname, char *NASport, int old)
{
- GDBM_FILE sessiondb;
- GDBM_FILE indexdb;
- datum key_datum, data_datum, save_datum;
- datum nextkey;
-
- ippool_key key;
- old_ippool_key old_key;
-
- ippool_info entry;
- struct in_addr ipaddr;
- uint8_t key_str[17];
- char hex_str[35];
- int num = 0;
- int mppp = 0;
- int mode = GDBM_WRITER;
- signed int rcode;
- int delete = 0;
- int port;
- int found = 0;
+ GDBM_FILE sessiondb;
+ GDBM_FILE indexdb;
+ datum key_datum, data_datum, save_datum;
+ datum nextkey;
+
+ ippool_key key;
+ old_ippool_key old_key;
+
+ ippool_info entry;
+ struct in_addr ipaddr;
+ uint8_t key_str[17];
+ char hex_str[35];
+ int num = 0;
+ int mppp = 0;
+ int mode = GDBM_WRITER;
+ int rcode;
+ int delete = 0;
+ uint16_t port;
+ bool found = false;
sessiondb = gdbm_open(sessiondbname, 512, mode, 0,NULL);
indexdb = gdbm_open(indexdbname, 512, mode, 0,NULL);
data_datum = gdbm_fetch(sessiondb, key_datum);
if (data_datum.dptr != NULL){
- found = 1;
+ found = true;
memcpy(&entry, data_datum.dptr, sizeof(ippool_info));
if (entry.active){
if ((key_datum.dsize != sizeof(struct ippool_key)) &&
(key_datum.dsize != sizeof(struct old_ippool_key))) {
- goto next;
+ goto next;
}
if (old) {
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
CPP C preprocessor
Use these variables to override the choices made by `configure' or to help
} # ac_fn_c_try_link
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+
# ac_fn_c_try_run LINENO
# ----------------------
# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=krb5.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lk5crypto"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lk5crypto"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libk5crypto${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libk5crypto.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lcrypto"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lcrypto"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libcrypto${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libcrypto.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lcom_err"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lcom_err"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libcom_err${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libcom_err.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lkrb5"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lkrb5"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libkrb5${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libkrb5.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lkrb5"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lkrb5"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libkrb5${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libkrb5.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
LDFLAGS="${LDFLAGS} ${SMART_LIBS}"
CFLAGS="${CFLAGS} ${SMART_CFLAGS}"
+ for ac_func in krb5_get_error_message krb5_free_error_string krb5_free_error_message
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+ if test "x$ac_cv_func_krb5_get_error_message" == xyes; then
+ krb5mod_cflags="${krb5mod_cflags} -D HAVE_KRB5_GET_ERROR_MESSAGE"
+ fi
+ if test "x$ac_cv_func_krb5_free_error_message" == xyes; then
+ krb5mod_cflags="${krb5mod_cflags} -D HAVE_KRB5_FREE_ERROR_MESSAGE"
+ fi
+ if test "x$ac_cv_func_krb5_free_error_string" == xyes; then
+ krb5mod_cflags="${krb5mod_cflags} -D HAVE_KRB5_FREE_ERROR_STRING"
+ fi
+
if test "$krb5threadsafe" != "no"; then
krb5threadsafe=
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lkrb5"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lkrb5"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libkrb5${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libkrb5.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=com_err.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=et/com_err.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
CFLAGS="${CFLAGS} ${SMART_CFLAGS}"
dnl #
+ dnl # Check how to free things returned by krb5_get_error_message
+ dnl #
+ AC_CHECK_FUNCS([krb5_get_error_message krb5_free_error_string krb5_free_error_message])
+ if test "x$ac_cv_func_krb5_get_error_message" == xyes; then
+ krb5mod_cflags="${krb5mod_cflags} -D HAVE_KRB5_GET_ERROR_MESSAGE"
+ fi
+ if test "x$ac_cv_func_krb5_free_error_message" == xyes; then
+ krb5mod_cflags="${krb5mod_cflags} -D HAVE_KRB5_FREE_ERROR_MESSAGE"
+ fi
+ if test "x$ac_cv_func_krb5_free_error_string" == xyes; then
+ krb5mod_cflags="${krb5mod_cflags} -D HAVE_KRB5_FREE_ERROR_STRING"
+ fi
+
+ dnl #
dnl # Only check if version checks have not found kerberos to be thread unsafe
dnl #
if test "$krb5threadsafe" != "no"; then
#include <freeradius-devel/radiusd.h>
#include "krb5.h"
-#ifdef HEIMDAL_KRB5
+#ifdef HAVE_KRB5_GET_ERROR_MESSAGE
# define KRB5_STRERROR_BUFSIZE (2048)
fr_thread_local_setup(char *, krb5_error_buffer) /* macro */
msg = krb5_get_error_message(context, code);
if (msg) {
strlcpy(buffer, msg, KRB5_STRERROR_BUFSIZE);
+#ifdef HAVE_KRB5_FREE_ERROR_MESSAGE
krb5_free_error_message(context, msg);
+#elif defined(HAVE_KRB5_FREE_ERROR_STRING)
+ {
+ char *free;
+
+ memcpy(&free, &msg, sizeof(free));
+ krb5_free_error_string(context, free);
+ }
+#else
+# error "No way to free error strings, missing krb5_free_error_message() and krb5_free_error_string()"
+#endif
} else {
strlcpy(buffer, "Unknown error", KRB5_STRERROR_BUFSIZE);
}
if (conn->keytab) {
krb5_kt_close(conn->context, conn->keytab);
}
+
+#ifdef HEIMDAL_KRB5
+ if (conn->ccache) {
+ krb5_cc_destroy(conn->context, conn->ccache);
+ }
+#endif
+
return 0;
}
MEM(conn = talloc_zero(instance, rlm_krb5_handle_t));
ret = krb5_init_context(&conn->context);
if (ret) {
- EDEBUG("rlm_krb5 (%s): Context initialisation failed: %s", inst->xlat_name,
+ ERROR("rlm_krb5 (%s): Context initialisation failed: %s", inst->xlat_name,
rlm_krb5_error(NULL, ret));
return NULL;
}
#ifdef HEIMDAL_KRB5
- /*
- * Setup krb5_verify_user options
- *
- * Not entirely sure this is necessary, but as we use context
- * to get the cache handle, we probably do have to do this with
- * the cloned context.
- */
- krb5_cc_default(conn->context, &conn->ccache);
+ ret = krb5_cc_new_unique(conn->context, "MEMORY", NULL, &conn->ccache);
+ if (ret) {
+ ERROR("rlm_krb5 (%s): Credential cache creation failed: %s", inst->xlat_name,
+ rlm_krb5_error(conn->context, ret));
+
+ return NULL;
+ }
krb5_verify_opt_init(&conn->options);
krb5_verify_opt_set_ccache(&conn->options, conn->ccache);
* MIT Kerberos uses comm_err, so the macro just expands to a call
* to error_message.
*/
-#ifndef HEIMDAL_KRB5
+#ifndef HAVE_KRB5_GET_ERROR_MESSAGE
# ifdef ET_COMM_ERR
# include <et/com_err.h>
# else
#include "krb5.h"
static const CONF_PARSER module_config[] = {
- { "keytab", PW_TYPE_STRING_PTR, offsetof(rlm_krb5_t, keytabname), NULL, NULL },
- { "service_principal", PW_TYPE_STRING_PTR, offsetof(rlm_krb5_t,service_princ), NULL, NULL },
+ { "keytab", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_krb5_t, keytabname), NULL },
+ { "service_principal", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_krb5_t, service_princ), NULL },
{ NULL, -1, 0, NULL, NULL }
};
-static int krb5_detach(void *instance)
+static int mod_detach(void *instance)
{
rlm_krb5_t *inst = instance;
return 0;
}
-static int krb5_instantiate(CONF_SECTION *conf, void *instance)
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
rlm_krb5_t *inst = instance;
krb5_error_code ret;
DEBUG("Using MIT Kerberos library");
#endif
-#ifndef KRB5_IS_THREAD_SAFE
if (!krb5_is_thread_safe()) {
- DEBUGI("libkrb5 is not threadsafe, recompile it, and the server with thread support enabled");
- WDEBUG("rlm_krb5 will run in single threaded mode, performance may be degraded");
+/*
+ * rlm_krb5 was built as threadsafe
+ */
+#ifdef KRB5_IS_THREAD_SAFE
+ ERROR("Build time libkrb5 was threadsafe, but run time library claims not to be");
+ ERROR("Modify runtime linker path (LD_LIBRARY_PATH on most systems), to prefer threadsafe libkrb5");
+ return -1;
+/*
+ * rlm_krb5 was not built as threadsafe
+ */
+#else
+ WARN("libkrb5 is not threadsafe, recompile it with thread support enabled ("
+# ifdef HEIMDAL_KRB5
+ "--enable-pthread-support"
+# else
+ "--disable-thread-support=no"
+# endif
+ ")");
+ WARN("rlm_krb5 will run in single threaded mode, performance may be degraded");
} else {
- WDEBUG("Build time libkrb5 was not threadsafe, but run time library claims to be");
- WDEBUG("Reconfigure and recompile rlm_krb5 to enable thread support");
- }
+ WARN("Build time libkrb5 was not threadsafe, but run time library claims to be");
+ WARN("Reconfigure and recompile rlm_krb5 to enable thread support");
#endif
+ }
+
inst->xlat_name = cf_section_name2(conf);
if (!inst->xlat_name) {
inst->xlat_name = cf_section_name1(conf);
*/
if (request->password->da->attr != PW_USER_PASSWORD) {
REDEBUG("Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".",
- request->password->da->name);
+ request->password->da->name);
return RLM_MODULE_INVALID;
}
return RLM_MODULE_OK;
}
+/** Log error message and return appropriate rcode
+ *
+ * Translate kerberos error codes into return codes.
+ * @param request Current request.
+ * @param ret code from kerberos.
+ * @param conn used in the last operation.
+ */
+static rlm_rcode_t krb5_process_error(REQUEST *request, rlm_krb5_handle_t *conn, int ret)
+{
+ rad_assert(ret != 0);
+ rad_assert(conn); /* Silences warnings */
+
+ switch (ret) {
+ case KRB5_LIBOS_BADPWDMATCH:
+ case KRB5KRB_AP_ERR_BAD_INTEGRITY:
+ REDEBUG("Provided password was incorrect (%i): %s", ret, rlm_krb5_error(conn->context, ret));
+ return RLM_MODULE_REJECT;
+
+ case KRB5KDC_ERR_KEY_EXP:
+ case KRB5KDC_ERR_CLIENT_REVOKED:
+ case KRB5KDC_ERR_SERVICE_REVOKED:
+ REDEBUG("Account has been locked out (%i): %s", ret, rlm_krb5_error(conn->context, ret));
+ return RLM_MODULE_USERLOCK;
+
+ case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
+ RDEBUG("User not found (%i): %s", ret, rlm_krb5_error(conn->context, ret));
+ return RLM_MODULE_NOTFOUND;
+
+ default:
+ REDEBUG("Error verifying credentials (%i): %s", ret, rlm_krb5_error(conn->context, ret));
+ return RLM_MODULE_FAIL;
+ }
+}
+
#ifdef HEIMDAL_KRB5
/*
* Validate user/pass (Heimdal)
*/
-static rlm_rcode_t krb5_auth(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
{
rlm_krb5_t *inst = instance;
rlm_rcode_t rcode;
#ifdef KRB5_IS_THREAD_SAFE
conn = fr_connection_get(inst->pool);
- if (!conn) {
- REDEBUG("All krb5 contexts are in use");
-
- return RLM_MODULE_FAIL;
- }
+ if (!conn) return RLM_MODULE_FAIL;
#else
conn = inst->conn;
#endif
*/
ret = krb5_verify_user_opt(conn->context, client, request->password->vp_strvalue, &conn->options);
if (ret) {
- switch (ret) {
- case KRB5_LIBOS_BADPWDMATCH:
- case KRB5KRB_AP_ERR_BAD_INTEGRITY:
- REDEBUG("Provided password was incorrect (%i): %s", ret, rlm_krb5_error(conn->context, ret));
- rcode = RLM_MODULE_REJECT;
- break;
-
- case KRB5KDC_ERR_KEY_EXP:
- case KRB5KDC_ERR_CLIENT_REVOKED:
- case KRB5KDC_ERR_SERVICE_REVOKED:
- REDEBUG("Account has been locked out (%i): %s", ret, rlm_krb5_error(conn->context, ret));
- rcode = RLM_MODULE_USERLOCK;
- break;
-
- case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
- RDEBUG("User not found: %s (%i)", ret, rlm_krb5_error(conn->context, ret));
- rcode = RLM_MODULE_NOTFOUND;
-
- default:
- REDEBUG("Error verifying credentials (%i): %s", ret, rlm_krb5_error(conn->context, ret));
- rcode = RLM_MODULE_FAIL;
- break;
- }
-
+ rcode = krb5_process_error(request, conn, ret);
goto cleanup;
}
- cleanup:
+ /*
+ * krb5_verify_user_opt adds the credentials to the ccache
+ * we specified with krb5_verify_opt_set_ccache.
+ *
+ * To make sure we don't accumulate thousands of sets of
+ * credentials, remove them again here.
+ *
+ * @todo This should definitely be optional, which means writing code for the MIT
+ * variant as well.
+ */
+ {
+ krb5_cc_cursor cursor;
+ krb5_creds cred;
+
+ krb5_cc_start_seq_get(conn->context, conn->ccache, &cursor);
+ for ((ret = krb5_cc_next_cred(conn->context, conn->ccache, &cursor, &cred));
+ ret == 0;
+ (ret = krb5_cc_next_cred(conn->context, conn->ccache, &cursor, &cred))) {
+ krb5_cc_remove_cred(conn->context, conn->ccache, 0, &cred);
+ }
+ krb5_cc_end_seq_get(conn->context, conn->ccache, &cursor);
+ }
+
+cleanup:
if (client) {
krb5_free_principal(conn->context, client);
}
/*
* Validate userid/passwd (MIT)
*/
-static rlm_rcode_t krb5_auth(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
{
rlm_krb5_t *inst = instance;
rlm_rcode_t rcode;
#ifdef KRB5_IS_THREAD_SAFE
conn = fr_connection_get(inst->pool);
- if (!conn) {
- REDEBUG("All krb5 contexts are in use");
-
- return RLM_MODULE_FAIL;
- }
+ if (!conn) return RLM_MODULE_FAIL;
#else
conn = inst->conn;
#endif
* Retrieve the TGT from the TGS/KDC and check we can decrypt it.
*/
memcpy(&password, &request->password->vp_strvalue, sizeof(password));
+ RDEBUG("Retrieving and decrypting TGT");
ret = krb5_get_init_creds_password(conn->context, &init_creds, client, password,
NULL, NULL, 0, NULL, inst->gic_options);
if (ret) {
- error:
- switch (ret) {
- case KRB5_LIBOS_BADPWDMATCH:
- case KRB5KRB_AP_ERR_BAD_INTEGRITY:
- REDEBUG("Provided password was incorrect (%i): %s", ret, rlm_krb5_error(conn->context, ret));
- rcode = RLM_MODULE_REJECT;
- break;
-
- case KRB5KDC_ERR_KEY_EXP:
- case KRB5KDC_ERR_CLIENT_REVOKED:
- case KRB5KDC_ERR_SERVICE_REVOKED:
- REDEBUG("Account has been locked out (%i): %s", ret, rlm_krb5_error(conn->context, ret));
- rcode = RLM_MODULE_USERLOCK;
- break;
-
- case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
- REDEBUG("User not found (%i): %s", ret, rlm_krb5_error(conn->context, ret));
- rcode = RLM_MODULE_NOTFOUND;
- break;
-
- default:
- REDEBUG("Error retrieving or verifying credentials (%i): %s", ret,
- rlm_krb5_error(conn->context, ret));
- rcode = RLM_MODULE_FAIL;
- break;
- }
-
+ rcode = krb5_process_error(request, conn, ret);
goto cleanup;
}
- RDEBUG("Successfully retrieved and decrypted TGT");
-
+ RDEBUG("Attempting to authenticate against service principal");
ret = krb5_verify_init_creds(conn->context, &init_creds, inst->server, conn->keytab, NULL, inst->vic_options);
- if (ret) goto error;
+ if (ret) {
+ rcode = krb5_process_error(request, conn, ret);
+ }
- cleanup:
+cleanup:
if (client) {
krb5_free_principal(conn->context, client);
}
module_t rlm_krb5 = {
RLM_MODULE_INIT,
"krb5",
- RLM_TYPE_CHECK_CONFIG_SAFE | RLM_TYPE_HUP_SAFE
+ RLM_TYPE_HUP_SAFE
#ifdef KRB5_IS_THREAD_SAFE
| RLM_TYPE_THREAD_SAFE
#endif
,
sizeof(rlm_krb5_t),
module_config,
- krb5_instantiate, /* instantiation */
- krb5_detach, /* detach */
+ mod_instantiate, /* instantiation */
+ mod_detach, /* detach */
{
- krb5_auth, /* authenticate */
+ mod_authenticate, /* authenticate */
NULL, /* authorize */
NULL, /* pre-accounting */
NULL, /* accounting */
#include <freeradius-devel/rad_assert.h>
#include "ldap.h"
+/** Callback for radius_map2request
+ *
+ * Performs exactly the same job as radius_map2vp, but pulls attribute values from LDAP entries
+ *
+ * @see radius_map2vp
+ */
static int rlm_ldap_map_getvalue(VALUE_PAIR **out, REQUEST *request, value_pair_map_t const *map, void *ctx)
{
rlm_ldap_result_t *self = ctx;
vp_cursor_t cursor;
int i;
- paircursor(&cursor, &head);
+ fr_cursor_init(&cursor, &head);
+
+ switch (map->dst->type) {
+ /*
+ * This is a mapping in the form of:
+ * <list>: += <ldap attr>
+ *
+ * Where <ldap attr> is:
+ * <list>:<attr> <op> <value>
+ *
+ * It is to allow for legacy installations which stored
+ * RADIUS control and reply attributes in separate LDAP
+ * attributes.
+ */
+ case VPT_TYPE_LIST:
+ for (i = 0; i < self->count; i++) {
+ value_pair_map_t *attr = NULL;
+
+ RDEBUG3("Parsing valuepair string \"%s\"", self->values[i]->bv_val);
+ if (radius_strpair2map(&attr, request, self->values[i]->bv_val,
+ map->dst->vpt_request, map->dst->vpt_list,
+ REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
+ RWDEBUG("Failed parsing \"%s\" as valuepair, skipping...", self->values[i]->bv_val);
+ continue;
+ }
+
+ if (attr->dst->vpt_request != map->dst->vpt_request) {
+ RWDEBUG("valuepair \"%s\" has conflicting request qualifier (%s vs %s), skipping...",
+ self->values[i]->bv_val,
+ fr_int2str(request_refs, attr->dst->vpt_request, "<INVALID>"),
+ fr_int2str(request_refs, map->dst->vpt_request, "<INVALID>"));
+ next_pair:
+ talloc_free(attr);
+ continue;
+ }
+
+ if ((attr->dst->vpt_list != map->dst->vpt_list)) {
+ RWDEBUG("valuepair \"%s\" has conflicting list qualifier (%s vs %s), skipping...",
+ self->values[i]->bv_val,
+ fr_int2str(pair_lists, attr->dst->vpt_list, "<INVALID>"),
+ fr_int2str(pair_lists, map->dst->vpt_list, "<INVALID>"));
+ goto next_pair;
+ }
+
+ if (radius_map2vp(&vp, request, attr, NULL) < 0) {
+ RWDEBUG("Failed creating attribute for \"%s\", skipping...", self->values[i]->bv_val);
+ goto next_pair;
+ }
+
+ fr_cursor_insert(&cursor, vp);
+ talloc_free(attr);
+ }
+ break;
/*
* Iterate over all the retrieved values,
* don't try and be clever about changing operators
* just use whatever was set in the attribute map.
*/
- for (i = 0; i < self->count; i++) {
- vp = pairalloc(request, map->dst->da);
- rad_assert(vp);
+ case VPT_TYPE_ATTR:
+ for (i = 0; i < self->count; i++) {
+ if (!self->values[i]->bv_len) continue;
+
+ vp = pairalloc(request, map->dst->vpt_da);
+ rad_assert(vp);
- if (!pairparsevalue(vp, self->values[i])) {
- RDEBUG("Failed parsing value for \"%s\"", map->dst->da->name);
+ if (pairparsevalue(vp, self->values[i]->bv_val, self->values[i]->bv_len) < 0) {
+ RDEBUG("Failed parsing value for \"%s\"", map->dst->vpt_da->name);
- talloc_free(vp);
- continue;
+ talloc_free(vp);
+ continue;
+ }
+
+ vp->op = map->op;
+ fr_cursor_insert(&cursor, vp);
}
+ break;
- vp->op = map->op;
- pairinsert(&cursor, vp);
+ default:
+ rad_assert(0);
}
*out = head;
* to do rlm_ldap specific checks here.
*/
for (map = *head; map != NULL; map = map->next) {
- if (map->dst->type != VPT_TYPE_ATTR) {
- cf_log_err(map->ci, "Left operand must be an attribute ref");
-
- return -1;
- }
+ switch (map->dst->type) {
+ case VPT_TYPE_LIST:
+ if (map->op != T_OP_ADD) {
+ cf_log_err(map->ci, "Only '+=' operator is permitted for valuepair to list mapping");
+ return -1;
+ }
- if (map->src->type == VPT_TYPE_LIST) {
- cf_log_err(map->ci, "Right operand must not be a list");
+ case VPT_TYPE_ATTR:
+ break;
+ default:
+ cf_log_err(map->ci, "valuepair destination must be an attribute or list");
return -1;
}
- if (map->src->type == VPT_TYPE_EXEC) {
- cf_log_err(map->ci, "Exec values are not allowed");
-
+ switch (map->src->type) {
+ case VPT_TYPE_LIST:
+ cf_log_err(map->ci, "LDAP attribute name cannot be derived from a list");
return -1;
+
+ default:
+ break;
}
/*
* and has no idea what they're doing, or they're authenticating the user using a different
* method.
*/
- if (!inst->expect_password && map->dst->da && (map->dst->type == VPT_TYPE_ATTR)) {
- switch (map->dst->da->attr) {
+ if (!inst->expect_password && map->dst->vpt_da && (map->dst->type == VPT_TYPE_ATTR)) {
+ switch (map->dst->vpt_da->attr) {
case PW_CLEARTEXT_PASSWORD:
case PW_NT_PASSWORD:
case PW_USER_PASSWORD:
* Because you just know someone is going to map NT-Password to the
* request list, and then complain it's not working...
*/
- if (map->dst->list != PAIR_LIST_CONTROL) {
- LDAP_DBGW("Mapping LDAP (%s) attribute to password \"reference\" attribute "
+ if (map->dst->vpt_list != PAIR_LIST_CONTROL) {
+ LDAP_DBGW("Mapping LDAP (%s) attribute to \"known good\" password attribute "
"(%s) in %s list. This is probably *NOT* the correct list, "
- "you should prepend \"control:\" to \"reference\" attribute "
+ "you should prepend \"control:\" to password attribute "
"(control:%s)",
- map->src->name, map->dst->da->name,
- fr_int2str(pair_lists, map->dst->list, "<invalid>"),
- map->dst->da->name);
+ map->src->name, map->dst->vpt_da->name,
+ fr_int2str(pair_lists, map->dst->vpt_list, "<invalid>"),
+ map->dst->vpt_da->name);
}
inst->expect_password = true;
if (!name) return;
switch (map->src->type) {
+ case VPT_TYPE_EXEC:
case VPT_TYPE_XLAT:
case VPT_TYPE_ATTR:
rad_const_free(name);
{
value_pair_map_t const *map;
unsigned int total = 0;
- size_t len;
VALUE_PAIR *found, **from = NULL;
REQUEST *context;
for (map = maps; map != NULL; map = map->next) {
switch (map->src->type) {
case VPT_TYPE_XLAT:
- {
- char *exp = NULL;
+ {
+ ssize_t len;
+ char *exp = NULL;
- len = radius_xlat(exp, 0, request, map->src->name, NULL, NULL);
- if (len <= 0) {
- RDEBUG("Expansion of LDAP attribute \"%s\" failed", map->src->name);
+ len = radius_axlat(&exp, request, map->src->name, NULL, NULL);
+ if (len < 0) {
+ RDEBUG("Expansion of LDAP attribute \"%s\" failed", map->src->name);
- goto error;
- }
-
- expanded->attrs[total++] = exp;
- break;
+ goto error;
}
+ expanded->attrs[total++] = exp;
+ break;
+ }
+
case VPT_TYPE_ATTR:
context = request;
- if (radius_request(&context, map->src->request) == 0) {
- from = radius_list(context, map->src->list);
+ if (radius_request(&context, map->src->vpt_request) == 0) {
+ from = radius_list(context, map->src->vpt_list);
}
if (!from) continue;
- found = pairfind(*from, map->src->da->attr, map->src->da->vendor, TAG_ANY);
+ found = pairfind(*from, map->src->vpt_da->attr, map->src->vpt_da->vendor, TAG_ANY);
if (!found) continue;
- expanded->attrs[total++] = talloc_strdup(request, found->vp_strvalue);
+ expanded->attrs[total++] = talloc_typed_strdup(request, found->vp_strvalue);
+ break;
+
+ case VPT_TYPE_EXEC:
+ {
+ char answer[1024];
+ VALUE_PAIR **input_pairs = NULL;
+ int result;
+
+ input_pairs = radius_list(request, PAIR_LIST_REQUEST);
+ result = radius_exec_program(request, map->src->name, true, true, answer,
+ sizeof(answer), EXEC_TIMEOUT,
+ input_pairs ? *input_pairs : NULL, NULL);
+ if (result != 0) {
+ return -1;
+ }
+
+ expanded->attrs[total++] = talloc_typed_strdup(request, answer);
+ }
break;
case VPT_TYPE_LITERAL:
expanded->attrs[total++] = map->src->name;
break;
+
default:
rad_assert(0);
error:
return -1;
}
-
}
rad_assert(total < LDAP_MAX_ATTRMAP);
for (map = expanded->maps; map != NULL; map = map->next) {
name = expanded->attrs[total++];
- result.values = ldap_get_values(handle, entry, name);
+ /*
+ * Binary safe
+ */
+ result.values = ldap_get_values_len(handle, entry, name);
if (!result.values) {
RDEBUG3("Attribute \"%s\" not found in LDAP object", name);
* Find out how many values there are for the
* attribute and extract all of them.
*/
- result.count = ldap_count_values(result.values);
+ result.count = ldap_count_values_len(result.values);
/*
* If something bad happened, just skip, this is probably
* a case of the dst being incorrect for the current
* request context
*/
- if (radius_map2request(request, map, name, rlm_ldap_map_getvalue, &result) == -1) {
+ if (radius_map2request(request, map, rlm_ldap_map_getvalue, &result) == -1) {
return; /* Fail */
}
next:
- ldap_value_free(result.values);
+ ldap_value_free_len(result.values);
}
/*
count = ldap_count_values(values);
for (i = 0; i < count; i++) {
+ value_pair_map_t *attr;
+
RDEBUG3("Parsing attribute string '%s'", values[i]);
- if (radius_str2vp(request, values[i],
- REQUEST_CURRENT, PAIR_LIST_REPLY,
- REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
+ if (radius_strpair2map(&attr, request, values[i],
+ REQUEST_CURRENT, PAIR_LIST_REPLY,
+ REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
RWDEBUG("Failed parsing '%s' value \"%s\" as valuepair, skipping...",
inst->valuepair_attr, values[i]);
+ continue;
+ }
+ if (radius_map2request(request, attr, radius_map2vp, NULL) < 0) {
+ RWDEBUG("Failed adding \"%s\" to request, skipping...", values[i]);
}
+ talloc_free(attr);
}
ldap_value_free(values);
* @return One of the RLM_MODULE_* values.
*/
rlm_rcode_t rlm_ldap_map_profile(ldap_instance_t const *inst, REQUEST *request, ldap_handle_t **pconn,
- char const *dn, rlm_ldap_map_xlat_t const *expanded)
+ char const *dn, rlm_ldap_map_xlat_t const *expanded)
{
rlm_rcode_t rcode = RLM_MODULE_OK;
ldap_rcode_t status;
rcode = RLM_MODULE_NOTFOUND;
- goto free_result;
+ goto free_result;
}
RDEBUG("Processing profile attributes");
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
sm_func_safe=`echo "ldap_init" | 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 ldap_init in -lldap_r in $try" >&5
$as_echo_n "checking for ldap_init in -lldap_r in $try... " >&6; }
- LIBS="-L$try -lldap_r $old_LIBS -Wl,-rpath,$try"
+ LIBS="-lldap_r $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
extern char ldap_init();
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-L$try -lldap_r -Wl,-rpath,$try"
+ smart_lib="-lldap_r"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
break
conftest$ac_exeext conftest.$ac_ext
done
LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_lib" = "x"; then
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lldap_r"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lldap_r"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libldap_r${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libldap_r.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
for try in $smart_lib_dir /usr/local/lib /opt/lib; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldap_init in -lldap_r in $try" >&5
$as_echo_n "checking for ldap_init in -lldap_r in $try... " >&6; }
- LIBS="-L$try -lldap_r $old_LIBS -Wl,-rpath,$try"
+ LIBS="-lldap_r $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
extern char ldap_init();
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-L$try -lldap_r -Wl,-rpath,$try"
+ smart_lib="-lldap_r"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
break
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_lib $old_LIBS"
- SMART_LIBS="$smart_lib $SMART_LIBS"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
fi
if test "x$ac_cv_lib_ldap_r_ldap_init" != "xyes"; then
sm_func_safe=`echo "ldap_init" | 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 ldap_init in -lldap in $try" >&5
$as_echo_n "checking for ldap_init in -lldap in $try... " >&6; }
- LIBS="-L$try -lldap $old_LIBS -Wl,-rpath,$try"
+ LIBS="-lldap $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
extern char ldap_init();
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-L$try -lldap -Wl,-rpath,$try"
+ smart_lib="-lldap"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
break
conftest$ac_exeext conftest.$ac_ext
done
LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_lib" = "x"; then
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lldap"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lldap"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libldap${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libldap.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
for try in $smart_lib_dir /usr/local/lib /opt/lib; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldap_init in -lldap in $try" >&5
$as_echo_n "checking for ldap_init in -lldap in $try... " >&6; }
- LIBS="-L$try -lldap $old_LIBS -Wl,-rpath,$try"
+ LIBS="-lldap $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
extern char ldap_init();
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-L$try -lldap -Wl,-rpath,$try"
+ smart_lib="-lldap"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
break
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_lib $old_LIBS"
- SMART_LIBS="$smart_lib $SMART_LIBS"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
fi
if test "x$ac_cv_lib_ldap_ldap_init" != "xyes"; then
ac_safe=`echo "ldap.h" | sed 'y%./+-%__pm%'`
-old_CFLAGS="$CFLAGS"
+old_CPPFLAGS="$CPPFLAGS"
smart_include=
smart_include_dir=
for try in $smart_try_dir; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldap.h in $try" >&5
$as_echo_n "checking for ldap.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_include" = "x"; then
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=ldap.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
for try in $smart_include_dir /usr/local/include /opt/include; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldap.h in $try" >&5
$as_echo_n "checking for ldap.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_include" != "x"; then
eval "ac_cv_header_$ac_safe=yes"
- CFLAGS="$old_CFLAGS $smart_include"
- SMART_CFLAGS="$SMART_CFLAGS $smart_include"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
fi
if test "$ac_cv_header_ldap_h" != "yes"; then
if test "x$fail" = "x"; then
ac_fn_c_check_func "$LINENO" "ldap_start_tls_s" "ac_cv_func_ldap_start_tls_s"
if test "x$ac_cv_func_ldap_start_tls_s" = xyes; then :
- SMART_CFLAGS="$SMART_CFLAGS -DHAVE_LDAP_START_TLS"
+ SMART_CPPFLAGS="$SMART_CPPFLAGS -DHAVE_LDAP_START_TLS"
fi
ac_fn_c_check_func "$LINENO" "ldap_initialize" "ac_cv_func_ldap_initialize"
if test "x$ac_cv_func_ldap_initialize" = xyes; then :
- SMART_CFLAGS="$SMART_CFLAGS -DHAVE_LDAP_INITIALIZE"
+ SMART_CPPFLAGS="$SMART_CPPFLAGS -DHAVE_LDAP_INITIALIZE"
fi
- for ac_func in ldap_set_rebind_proc
+ for ac_func in ldap_set_rebind_proc
do :
ac_fn_c_check_func "$LINENO" "ldap_set_rebind_proc" "ac_cv_func_ldap_set_rebind_proc"
if test "x$ac_cv_func_ldap_set_rebind_proc" = xyes; then :
fi
done
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ldap_set_rebind_proc takes 3 arguments" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ldap_set_rebind_proc takes 3 arguments" >&5
$as_echo_n "checking whether ldap_set_rebind_proc takes 3 arguments... " >&6; }
if ${ac_cv_ldap_set_rebind_proc+:} false; then :
$as_echo_n "(cached) " >&6
else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
- #include <lber.h>
- #include <ldap.h>
+ #include <lber.h>
+ #include <ldap.h>
int
main ()
{
fi
mod_ldflags=$SMART_LIBS
-mod_cflags="$SMART_CFLAGS -DWITH_EDIR -DLDAP_DEPRECATED -DLDAP_SET_REBIND_PROC_ARGS=$ac_cv_ldap_set_rebind_proc"
+mod_cflags="$SMART_CPPFLAGS -DWITH_EDIR -DLDAP_DEPRECATED -DLDAP_SET_REBIND_PROC_ARGS=$ac_cv_ldap_set_rebind_proc"
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
if test "x$fail" = "x"; then
AC_CHECK_FUNC(ldap_start_tls_s,
- [ SMART_CFLAGS="$SMART_CFLAGS -DHAVE_LDAP_START_TLS" ])
+ [ SMART_CPPFLAGS="$SMART_CPPFLAGS -DHAVE_LDAP_START_TLS" ])
AC_CHECK_FUNC(ldap_initialize,
- [ SMART_CFLAGS="$SMART_CFLAGS -DHAVE_LDAP_INITIALIZE" ])
+ [ SMART_CPPFLAGS="$SMART_CPPFLAGS -DHAVE_LDAP_INITIALIZE" ])
- AC_CHECK_FUNCS(ldap_set_rebind_proc)
- AC_CACHE_CHECK(whether ldap_set_rebind_proc takes 3 arguments, ac_cv_ldap_set_rebind_proc, [
- AC_TRY_COMPILE([
- #include <lber.h>
- #include <ldap.h>], [ldap_set_rebind_proc(0, 0, 0);],
+ AC_CHECK_FUNCS(ldap_set_rebind_proc)
+ AC_CACHE_CHECK(whether ldap_set_rebind_proc takes 3 arguments, ac_cv_ldap_set_rebind_proc, [
+ AC_TRY_COMPILE([
+ #include <lber.h>
+ #include <ldap.h>], [ldap_set_rebind_proc(0, 0, 0);],
[ac_cv_ldap_set_rebind_proc=3],
[ac_cv_ldap_set_rebind_proc=2]) ])
fi
fi
mod_ldflags=$SMART_LIBS
-mod_cflags="$SMART_CFLAGS -DWITH_EDIR -DLDAP_DEPRECATED -DLDAP_SET_REBIND_PROC_ARGS=$ac_cv_ldap_set_rebind_proc"
+mod_cflags="$SMART_CPPFLAGS -DWITH_EDIR -DLDAP_DEPRECATED -DLDAP_SET_REBIND_PROC_ARGS=$ac_cv_ldap_set_rebind_proc"
AC_SUBST(mod_ldflags)
AC_SUBST(mod_cflags)
AC_SUBST(targetname)
* It'll probably only save a few ms in network latency, but it means we can send a query
* for the entire group list at once.
*/
- filter = talloc_asprintf(request, "%s%s%s",
+ filter = talloc_typed_asprintf(request, "%s%s%s",
inst->groupobj_filter ? "(&" : "",
inst->groupobj_filter ? inst->groupobj_filter : "",
names[0] && names[1] ? "(|" : "");
RDEBUG("Group name is \"%s\"", vals[0]);
- *out = talloc_strdup(request, vals[0]);
+ *out = talloc_typed_strdup(request, vals[0]);
finish:
if (result) {
* The easy case, were caching DNs and we got a DN.
*/
if (is_dn) {
- pairmake(request, &request->config_items, inst->group_da->name, vals[i], T_OP_ADD);
- RDEBUG("Added %s with value \"%s\" to control list", inst->group_da->name, vals[i]);
-
+ pairmake(request, &request->config_items, inst->cache_da->name, vals[i], T_OP_ADD);
+ RDEBUG("Added %s with value \"%s\" to control list", inst->cache_da->name, vals[i]);
/*
* We were told to cache DNs but we got a name, we now need to resolve
* this to a DN. Store all the group names in an array so we can do one query.
* The easy case, were caching names and we got a name.
*/
if (!is_dn) {
- pairmake(request, &request->config_items, inst->group_da->name, vals[i], T_OP_ADD);
- RDEBUG("Added %s with value \"%s\" to control list", inst->group_da->name, vals[i]);
+ pairmake(request, &request->config_items, inst->cache_da->name, vals[i], T_OP_ADD);
+ RDEBUG("Added control:%s with value \"%s\"", inst->cache_da->name, vals[i]);
/*
* We were told to cache names but we got a DN, we now need to resolve
* this to a name.
return rcode;
}
- pairmake(request, &request->config_items, inst->group_da->name, name, T_OP_ADD);
- RDEBUG("Added %s with value \"%s\" to control list", inst->group_da->name, name);
+ pairmake(request, &request->config_items, inst->cache_da->name, name, T_OP_ADD);
+ DEBUG("Added control:%s with value \"%s\"", inst->cache_da->name, name);
talloc_free(name);
}
}
dn_p = group_dn;
while(*dn_p) {
- pairmake(request, &request->config_items, inst->group_da->name, *dn_p, T_OP_ADD);
- RDEBUG("Added %s with value \"%s\" to control list", inst->group_da->name, *dn_p);
+ pairmake(request, &request->config_items, inst->cache_da->name, *dn_p, T_OP_ADD);
+ RDEBUG("Added control:%s with value \"%s\"", inst->cache_da->name, *dn_p);
ldap_memfree(*dn_p);
dn_p++;
do {
if (inst->cacheable_group_dn) {
dn = ldap_get_dn((*pconn)->handle, entry);
- pairmake(request, &request->config_items, inst->group_da->name, dn, T_OP_ADD);
- RDEBUG("Added %s with value \"%s\" to control list", inst->group_da->name, dn);
+ pairmake(request, &request->config_items, inst->cache_da->name, dn, T_OP_ADD);
+ RDEBUG("Added control:%s with value \"%s\"", inst->cache_da->name, dn);
ldap_memfree(dn);
}
continue;
}
- pairmake(request, &request->config_items, inst->group_da->name, *vals, T_OP_ADD);
- RDEBUG("Added %s with value \"%s\" to control list", inst->group_da->name, *vals);
+ pairmake(request, &request->config_items, inst->cache_da->name, *vals, T_OP_ADD);
+ RDEBUG("Added control:%s with value \"%s\"", inst->cache_da->name, *vals);
ldap_value_free(vals);
}
{
rlm_rcode_t rcode = RLM_MODULE_NOTFOUND, ret;
ldap_rcode_t status;
- int name_is_dn = false, value_is_dn = false;
+ bool name_is_dn = false, value_is_dn = false;
LDAPMessage *result = NULL;
LDAPMessage *entry = NULL;
*/
if (!name_is_dn && !value_is_dn) {
if (strcmp(vals[i], name) == 0){
- RDEBUG("User found. Comparison between membership: name, check: name]");
+ RDEBUG("User found. Comparison between membership: name, check: name");
rcode = RLM_MODULE_OK;
goto finish;
int ret;
vp_cursor_t cursor;
- paircursor(&cursor, &request->config_items);
- vp = pairfindnext(&cursor, inst->group_da->attr, inst->group_da->vendor, TAG_ANY);
+ fr_cursor_init(&cursor, &request->config_items);
+ vp = fr_cursor_next_by_num(&cursor, inst->cache_da->attr, inst->cache_da->vendor, TAG_ANY);
if (!vp) {
return RLM_MODULE_INVALID;
}
- for (; vp; vp = pairfindnext(&cursor, inst->group_da->attr, inst->group_da->vendor, TAG_ANY)) {
+ for (; vp; vp = fr_cursor_next_by_num(&cursor, inst->cache_da->attr, inst->cache_da->vendor, TAG_ANY)) {
ret = radius_compare_vps(request, check, vp);
if (ret == 0) {
RDEBUG2("User found. Matched cached membership");
char *srv_err = NULL; // Server's extended error message.
char *p, *a;
- int freeit = false; // Whether the message should be freed after being processed.
+ bool freeit = false; // Whether the message should be freed after being processed.
int len;
struct timeval tv; // Holds timeout values.
len = rlm_ldap_common_dn(dn, part_dn);
if (len < 0) break;
- our_err = talloc_asprintf(conn, "Match stopped here: [%.*s]%s", len, dn, part_dn ? part_dn : "");
+ our_err = talloc_typed_asprintf(conn, "Match stopped here: [%.*s]%s", len, dn, part_dn ? part_dn : "");
goto error_string;
if (lib_errno != srv_errno) {
a = talloc_asprintf_append(p, "LDAP lib error: %s (%u), srv error: %s (%u). ",
- ldap_err2string(lib_errno), lib_errno,
+ ldap_err2string(lib_errno), lib_errno,
ldap_err2string(srv_errno), srv_errno);
if (!a) {
talloc_free(p);
ldap_memfree(part_dn);
}
- if (our_err) {
- talloc_free(our_err);
- }
+ talloc_free(our_err);
if ((lib_errno || srv_errno) && *result) {
ldap_msgfree(*result);
* @return one of the LDAP_PROC_* values.
*/
ldap_rcode_t rlm_ldap_bind(ldap_instance_t const *inst, REQUEST *request, ldap_handle_t **pconn, char const *dn,
- char const *password, int retry)
+ char const *password, bool retry)
{
- ldap_rcode_t status;
+ ldap_rcode_t status = LDAP_PROC_ERROR;
int msgid;
char const *error = NULL;
char *extra = NULL;
+ int i, num;
+
rad_assert(*pconn && (*pconn)->handle);
+ rad_assert(!retry || inst->pool);
/*
* Bind as anonymous user
*/
if (!dn) dn = "";
-retry:
- msgid = ldap_bind((*pconn)->handle, dn, password, LDAP_AUTH_SIMPLE);
- /* We got a valid message ID */
- if (msgid >= 0) {
- if (request) {
- RDEBUG2("Waiting for bind result...");
- } else {
- DEBUG2("rlm_ldap (%s): Waiting for bind result...", inst->xlat_name);
+ /*
+ * For sanity, for when no connections are viable,
+ * and we can't make a new one.
+ */
+ num = retry ? fr_connection_get_num(inst->pool) : 0;
+ for (i = num; i >= 0; i--) {
+ msgid = ldap_bind((*pconn)->handle, dn, password, LDAP_AUTH_SIMPLE);
+ /* We got a valid message ID */
+ if (msgid >= 0) {
+ if (request) {
+ RDEBUG2("Waiting for bind result...");
+ } else {
+ DEBUG2("rlm_ldap (%s): Waiting for bind result...", inst->xlat_name);
+ }
}
- }
- status = rlm_ldap_result(inst, *pconn, msgid, dn, NULL, &error, &extra);
- switch (status) {
- case LDAP_PROC_SUCCESS:
- LDAP_DBG_REQ("Bind successful");
- break;
- case LDAP_PROC_NOT_PERMITTED:
- LDAP_ERR_REQ("Bind was not permitted: %s", error);
- LDAP_EXT_REQ();
+ status = rlm_ldap_result(inst, *pconn, msgid, dn, NULL, &error, &extra);
+ switch (status) {
+ case LDAP_PROC_SUCCESS:
+ LDAP_DBG_REQ("Bind successful");
+ break;
- break;
+ case LDAP_PROC_NOT_PERMITTED:
+ LDAP_ERR_REQ("Bind was not permitted: %s", error);
+ LDAP_EXT_REQ();
- case LDAP_PROC_REJECT:
- LDAP_ERR_REQ("Bind credentials incorrect: %s", error);
- LDAP_EXT_REQ();
+ break;
- break;
+ case LDAP_PROC_REJECT:
+ LDAP_ERR_REQ("Bind credentials incorrect: %s", error);
+ LDAP_EXT_REQ();
- case LDAP_PROC_RETRY:
- if (retry) {
- *pconn = fr_connection_reconnect(inst->pool, *pconn);
- if (*pconn) {
- LDAP_DBGW_REQ("Bind with %s to %s:%d failed: %s. Got new socket, retrying...",
- dn, inst->server, inst->port, error);
+ break;
- talloc_free(extra); /* don't leak debug info */
+ case LDAP_PROC_RETRY:
+ if (retry) {
+ *pconn = fr_connection_reconnect(inst->pool, *pconn);
+ if (*pconn) {
+ LDAP_DBGW_REQ("Bind with %s to %s:%d failed: %s. Got new socket, retrying...",
+ dn, inst->server, inst->port, error);
- goto retry;
- }
- };
+ talloc_free(extra); /* don't leak debug info */
- status = LDAP_PROC_ERROR;
+ continue;
+ }
+ };
+ status = LDAP_PROC_ERROR;
- /*
- * Were not allowed to retry, or there are no more
- * sockets, treat this as a hard failure.
- */
- /* FALL-THROUGH */
- default:
+ /*
+ * Were not allowed to retry, or there are no more
+ * sockets, treat this as a hard failure.
+ */
+ /* FALL-THROUGH */
+ default:
#ifdef HAVE_LDAP_INITIALIZE
- if (inst->is_url) {
- LDAP_ERR_REQ("Bind with %s to %s failed: %s", dn, inst->server, error);
- } else
+ if (inst->is_url) {
+ LDAP_ERR_REQ("Bind with %s to %s failed: %s", dn, inst->server, error);
+ } else
#endif
- {
- LDAP_ERR_REQ("Bind with %s to %s:%d failed: %s", dn, inst->server,
- inst->port, error);
+ {
+ LDAP_ERR_REQ("Bind with %s to %s:%d failed: %s", dn, inst->server,
+ inst->port, error);
+ }
+ LDAP_EXT_REQ();
+
+ break;
}
- LDAP_EXT_REQ();
break;
}
- if (extra) {
- talloc_free(extra);
+ if (retry && (i < 0)) {
+ LDAP_ERR_REQ("Hit reconnection limit");
+ status = LDAP_PROC_ERROR;
}
+ talloc_free(extra);
+
return status; /* caller closes the connection */
}
char const *error = NULL;
char *extra = NULL;
+ int i;
+
+
rad_assert(*pconn && (*pconn)->handle);
/*
(*pconn)->rebound = false;
}
- LDAP_DBG_REQ("Performing search in '%s' with filter '%s'", dn, filter);
-
+ if (filter) {
+ LDAP_DBG_REQ("Performing search in '%s' with filter '%s', scope '%s'", dn, filter,
+ fr_int2str(ldap_scope, scope, "<INVALID>"));
+ } else {
+ LDAP_DBG_REQ("Performing unfiltered search in '%s', scope '%s'", dn,
+ fr_int2str(ldap_scope, scope, "<INVALID>"));
+ }
/*
* If LDAP search produced an error it should also be logged
* to the ld. result should pick it up without us
*/
memset(&tv, 0, sizeof(tv));
tv.tv_sec = inst->res_timeout;
-retry:
- (void) ldap_search_ext((*pconn)->handle, dn, scope, filter, search_attrs, 0, NULL, NULL, &tv, 0, &msgid);
- LDAP_DBG_REQ("Waiting for search result...");
- status = rlm_ldap_result(inst, *pconn, msgid, dn, &our_result, &error, &extra);
- switch (status) {
+ /*
+ * For sanity, for when no connections are viable,
+ * and we can't make a new one.
+ */
+ for (i = fr_connection_get_num(inst->pool); i >= 0; i--) {
+ (void) ldap_search_ext((*pconn)->handle, dn, scope, filter, search_attrs,
+ 0, NULL, NULL, &tv, 0, &msgid);
+
+ LDAP_DBG_REQ("Waiting for search result...");
+ status = rlm_ldap_result(inst, *pconn, msgid, dn, &our_result, &error, &extra);
+ switch (status) {
case LDAP_PROC_SUCCESS:
break;
+
case LDAP_PROC_RETRY:
*pconn = fr_connection_reconnect(inst->pool, *pconn);
if (*pconn) {
talloc_free(extra); /* don't leak debug info */
- goto retry;
+ continue;
}
status = LDAP_PROC_ERROR;
if (extra) LDAP_ERR_REQ("%s", extra);
goto finish;
+ }
+
+ break;
+ }
+
+ if (i < 0) {
+ LDAP_ERR_REQ("Hit reconnection limit");
+ status = LDAP_PROC_ERROR;
+
+ goto finish;
}
count = ldap_count_entries((*pconn)->handle, our_result);
our_result = NULL;
}
- finish:
- if (extra) {
- talloc_free(extra);
- }
+finish:
+ talloc_free(extra);
/*
* We always need to get the result to count entries, but the caller
char const *error = NULL;
char *extra = NULL;
+ int i;
+
rad_assert(*pconn && (*pconn)->handle);
/*
(*pconn)->rebound = false;
}
- RDEBUG2("Modifying object with DN \"%s\"", dn);
- retry:
- (void) ldap_modify_ext((*pconn)->handle, dn, mods, NULL, NULL, &msgid);
+ /*
+ * For sanity, for when no connections are viable,
+ * and we can't make a new one.
+ */
+ for (i = fr_connection_get_num(inst->pool); i >= 0; i--) {
+ RDEBUG2("Modifying object with DN \"%s\"", dn);
+ (void) ldap_modify_ext((*pconn)->handle, dn, mods, NULL, NULL, &msgid);
+
+ RDEBUG2("Waiting for modify result...");
+ status = rlm_ldap_result(inst, *pconn, msgid, dn, NULL, &error, &extra);
+ switch (status) {
+ case LDAP_PROC_SUCCESS:
+ break;
+ case LDAP_PROC_RETRY:
+ *pconn = fr_connection_reconnect(inst->pool, *pconn);
+ if (*pconn) {
+ RWDEBUG("Modify failed: %s. Got new socket, retrying...", error);
- RDEBUG2("Waiting for modify result...");
- status = rlm_ldap_result(inst, *pconn, msgid, dn, NULL, &error, &extra);
- switch (status) {
- case LDAP_PROC_SUCCESS:
- break;
- case LDAP_PROC_RETRY:
- *pconn = fr_connection_reconnect(inst->pool, *pconn);
- if (*pconn) {
- RWDEBUG("Modify failed: %s. Got new socket, retrying...", error);
+ talloc_free(extra); /* don't leak debug info */
- talloc_free(extra); /* don't leak debug info */
+ continue;
+ }
- goto retry;
- }
+ status = LDAP_PROC_ERROR;
- status = LDAP_PROC_ERROR;
+ /* FALL-THROUGH */
+ default:
+ REDEBUG("Failed modifying object: %s", error);
+ REDEBUG("%s", extra);
- /* FALL-THROUGH */
- default:
- REDEBUG("Failed modifying object: %s", error);
- REDEBUG("%s", extra);
+ goto finish;
+ }
- goto finish;
+ break;
}
- finish:
- if (extra) {
- talloc_free(extra);
+ if (i < 0) {
+ LDAP_ERR_REQ("Hit reconnection limit");
+ status = LDAP_PROC_ERROR;
}
+finish:
+ talloc_free(extra);
+
return status;
}
char filter[LDAP_MAX_FILTER_STR_LEN];
char base_dn[LDAP_MAX_DN_STR_LEN];
- int freeit = false; //!< Whether the message should
+ bool freeit = false; //!< Whether the message should
//!< be freed after being processed.
*rcode = RLM_MODULE_FAIL;
if (vals) {
if (inst->access_positive) {
if (strncasecmp(vals[0], "false", 5) == 0) {
- RDEBUG("\"%s\" attribute exists but is set to 'false' - user locked out");
+ RDEBUG("\"%s\" attribute exists but is set to 'false' - user locked out",
+ inst->userobj_access_attr);
rcode = RLM_MODULE_USERLOCK;
}
/* RLM_MODULE_OK set above... */
!pairfind(request->config_items, PW_USER_PASSWORD, 0, TAG_ANY) &&
!pairfind(request->config_items, PW_PASSWORD_WITH_HEADER, 0, TAG_ANY) &&
!pairfind(request->config_items, PW_CRYPT_PASSWORD, 0, TAG_ANY)) {
- RWDEBUG("No \"reference\" password added. Ensure the admin user has permission to "
+ RWDEBUG("No \"known good\" password added. Ensure the admin user has permission to "
"read the password attribute");
RWDEBUG("PAP authentication will *NOT* work with Active Directory (if that is what you "
"were trying to configure)");
*/
if (inst->start_tls) {
if (inst->port == 636) {
- WDEBUG("Told to Start TLS on LDAPS port this will probably fail, please correct the "
+ WARN("Told to Start TLS on LDAPS port this will probably fail, please correct the "
"configuration");
}
* @param inst rlm_ldap configuration.
* @param request Current request (may be NULL).
*/
-ldap_handle_t *rlm_ldap_get_socket(ldap_instance_t const *inst, REQUEST *request)
+ldap_handle_t *rlm_ldap_get_socket(ldap_instance_t const *inst, UNUSED REQUEST *request)
{
- ldap_handle_t *conn;
-
- conn = fr_connection_get(inst->pool);
- if (!conn) {
- REDEBUG("All ldap connections are in use");
-
- return NULL;
- }
-
- return conn;
+ return fr_connection_get(inst->pool);
}
char const *server; //!< Initial server to bind to.
int is_url; //!< Whether ldap_is_ldap_url says 'server' is an
//!< ldap[s]:// url.
- int port; //!< Port to use when binding to the server.
+ uint16_t port; //!< Port to use when binding to the server.
char const *admin_dn; //!< DN we bind as when we need to query the LDAP
//!< directory.
//!< referrals on the same server, but won't bind to other
//!< servers.
- int ldap_debug; //!< Debug flag for the SDK.
+ uint32_t ldap_debug; //!< Debug flag for the SDK.
char const *xlat_name; //!< Instance name.
- int expect_password; //!< True if the user_map included a mapping between an LDAP
+ bool expect_password; //!< True if the user_map included a mapping between an LDAP
//!< attribute and one of our password reference attributes.
/*
int userobj_scope; //!< Search scope.
char const *userobj_membership_attr; //!< Attribute that describes groups the user is a member of.
- char *userobj_access_attr; //!< Attribute to check to see if the user should be locked out.
+ char const *userobj_access_attr; //!< Attribute to check to see if the user should be locked out.
bool access_positive; //!< If true the presence of the attribute will allow access,
//!< else it will deny access.
//!< resolution necessary to determine the DNs of those groups,
//!< then right them to the control list (LDAP-GroupDN).
+ char const *cache_attribute; //!< Sets the attribute we use when creating and retrieving
+ //!< cached group memberships.
+
+ DICT_ATTR const *cache_da; //!< The DA associated with this specific version of the
+ //!< rlm_ldap module.
+
DICT_ATTR const *group_da; //!< The DA associated with this specific version of the
//!< rlm_ldap module.
* Options
*/
- int net_timeout; //!< How long we wait for new connections to the LDAP server
+ uint32_t net_timeout; //!< How long we wait for new connections to the LDAP server
//!< to be established.
- int res_timeout; //!< How long we wait for a result from the server.
- int srv_timelimit; //!< How long the server should spent on a single request
+ uint32_t res_timeout; //!< How long we wait for a result from the server.
+ uint32_t srv_timelimit; //!< How long the server should spent on a single request
//!< (also bounded by value on the server).
#ifdef WITH_EDIR
- /*
+ /*
* eDir support
*/
- bool edir; //!< If true attempt to retrieve the user's Cleartext password
+ bool edir; //!< If true attempt to retrieve the user's cleartext password
//!< using the Universal Password feature of Novell eDirectory.
bool edir_autz; //!< If true, and we have the Universal Password, bind with it
//!< to perform additional authorisation checks.
* For keep-alives.
*/
#ifdef LDAP_OPT_X_KEEPALIVE_IDLE
- int keepalive_idle; //!< Number of seconds a connections needs to remain idle
+ uint32_t keepalive_idle; //!< Number of seconds a connections needs to remain idle
//!< before TCP starts sending keepalive probes.
#endif
#ifdef LDAP_OPT_X_KEEPALIVE_PROBES
- int keepalive_probes; //!< Number of missed timeouts before the connection is
+ uint32_t keepalive_probes; //!< Number of missed timeouts before the connection is
//!< dropped.
#endif
#ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL
- int keepalive_interval; //!< Interval between keepalive probes.
+ uint32_t keepalive_interval; //!< Interval between keepalive probes.
#endif
} ldap_instance_t;
} rlm_ldap_map_xlat_t;
typedef struct rlm_ldap_result {
- char **values;
- int count;
+ struct berval **values; //!< libldap struct containing bv_val (char *)
+ //!< and length bv_len.
+ int count; //!< Number of values.
} rlm_ldap_result_t;
typedef enum {
#define LDAP_EXT() if (extra) LDAP_ERR(extra)
#define LDAP_EXT_REQ() do { if (extra) { if (request) REDEBUG("%s", extra); else LDAP_ERR("%s", extra); }} while (0)
+extern FR_NAME_NUMBER const ldap_scope[];
+extern FR_NAME_NUMBER const ldap_tls_require_cert[];
+
/*
* ldap.c - Wrappers arounds OpenLDAP functions.
*/
ssize_t rlm_ldap_xlat_filter(REQUEST *request, char const **sub, size_t sublen, char *out, size_t outlen);
ldap_rcode_t rlm_ldap_bind(ldap_instance_t const *inst, REQUEST *request, ldap_handle_t **pconn, char const *dn,
- char const *password, int retry);
+ char const *password, bool retry);
char const *rlm_ldap_error_str(ldap_handle_t const *conn);
rlm_ldap_map_xlat_t const *expanded, LDAPMessage *entry);
rlm_rcode_t rlm_ldap_map_profile(ldap_instance_t const *inst, REQUEST *request, ldap_handle_t **pconn,
- char const *profile, rlm_ldap_map_xlat_t const *expanded);
+ char const *profile, rlm_ldap_map_xlat_t const *expanded);
/*
* clients.c - Dynamic clients (bulk load).
/*
* Scopes
*/
-const FR_NAME_NUMBER ldap_scope[] = {
+FR_NAME_NUMBER const ldap_scope[] = {
{ "sub", LDAP_SCOPE_SUB },
{ "one", LDAP_SCOPE_ONE },
{ "base", LDAP_SCOPE_BASE },
};
#ifdef LDAP_OPT_X_TLS_NEVER
-const FR_NAME_NUMBER ldap_tls_require_cert[] = {
+FR_NAME_NUMBER const ldap_tls_require_cert[] = {
{ "never", LDAP_OPT_X_TLS_NEVER },
{ "demand", LDAP_OPT_X_TLS_DEMAND },
{ "allow", LDAP_OPT_X_TLS_ALLOW },
/*
* Deprecated attributes
*/
- {"cacertfile", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, offsetof(ldap_instance_t, tls_ca_file), NULL, NULL},
- {"ca_file", PW_TYPE_FILE_INPUT, offsetof(ldap_instance_t, tls_ca_file), NULL, NULL},
+ { "cacertfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, ldap_instance_t, tls_ca_file), NULL },
+ { "ca_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, ldap_instance_t, tls_ca_file), NULL },
- {"cacertdir", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, offsetof(ldap_instance_t, tls_ca_path), NULL, NULL},
- {"ca_path", PW_TYPE_FILE_INPUT, offsetof(ldap_instance_t, tls_ca_path), NULL, NULL},
+ { "cacertdir", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, ldap_instance_t, tls_ca_path), NULL },
+ { "ca_path", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, ldap_instance_t, tls_ca_path), NULL },
- {"certfile", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, offsetof(ldap_instance_t, tls_certificate_file), NULL, NULL},
- {"certificate_file", PW_TYPE_FILE_INPUT, offsetof(ldap_instance_t, tls_certificate_file), NULL, NULL},
+ { "certfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, ldap_instance_t, tls_certificate_file), NULL },
+ { "certificate_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, ldap_instance_t, tls_certificate_file), NULL },
- {"keyfile", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, offsetof(ldap_instance_t, tls_private_key_file), NULL, NULL}, // OK if it changes on HUP
- {"private_key_file", PW_TYPE_FILE_INPUT, offsetof(ldap_instance_t, tls_private_key_file), NULL, NULL}, // OK if it changes on HUP
+ { "keyfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, ldap_instance_t, tls_private_key_file), NULL }, // OK if it changes on HUP
+ { "private_key_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, ldap_instance_t, tls_private_key_file), NULL }, // OK if it changes on HUP
- {"randfile", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, offsetof(ldap_instance_t, tls_random_file), NULL, NULL},
- {"random_file", PW_TYPE_FILE_INPUT, offsetof(ldap_instance_t, tls_random_file), NULL, NULL},
+ { "randfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, ldap_instance_t, tls_random_file), NULL },
+ { "random_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, ldap_instance_t, tls_random_file), NULL },
/*
* LDAP Specific TLS attributes
*/
- {"start_tls", PW_TYPE_BOOLEAN, offsetof(ldap_instance_t, start_tls), NULL, "no"},
- {"require_cert", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, tls_require_cert_str), NULL, NULL},
+ { "start_tls", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, ldap_instance_t, start_tls), "no" },
+ { "require_cert", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, tls_require_cert_str), NULL },
{ NULL, -1, 0, NULL, NULL }
};
static CONF_PARSER profile_config[] = {
- {"filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, profile_filter), NULL, "(&)"}, //!< Correct filter for
+ { "filter", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, profile_filter), "(&)" }, //!< Correct filter for
//!< when the DN is
//!< known.
- {"attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, profile_attr), NULL, NULL},
- {"default", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, default_profile), NULL, NULL},
+ { "attribute", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, profile_attr), NULL },
+ { "default", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, default_profile), NULL },
{ NULL, -1, 0, NULL, NULL }
};
* User configuration
*/
static CONF_PARSER user_config[] = {
- {"filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, userobj_filter), NULL, "(uid=%u)"},
- {"scope", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, userobj_scope_str), NULL, "sub"},
- {"base_dn", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t,userobj_base_dn), NULL, ""},
+ { "filter", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, userobj_filter), "(uid=%u)" },
+ { "scope", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, userobj_scope_str), "sub" },
+ { "base_dn", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, userobj_base_dn), "" },
- {"access_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, userobj_access_attr), NULL, NULL},
- {"access_positive", PW_TYPE_BOOLEAN, offsetof(ldap_instance_t, access_positive), NULL, "yes"},
+ { "access_attribute", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, userobj_access_attr), NULL },
+ { "access_positive", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, ldap_instance_t, access_positive), "yes" },
{ NULL, -1, 0, NULL, NULL }
};
* Group configuration
*/
static CONF_PARSER group_config[] = {
- {"filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, groupobj_filter), NULL, NULL},
- {"scope", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, groupobj_scope_str), NULL, "sub"},
- {"base_dn", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, groupobj_base_dn), NULL, ""},
+ { "filter", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, groupobj_filter), NULL },
+ { "scope", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, groupobj_scope_str), "sub" },
+ { "base_dn", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, groupobj_base_dn), "" },
- {"name_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, groupobj_name_attr), NULL, "cn"},
- {"membership_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, userobj_membership_attr), NULL, NULL},
- {"membership_filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, groupobj_membership_filter), NULL, NULL},
- {"cacheable_name", PW_TYPE_BOOLEAN, offsetof(ldap_instance_t, cacheable_group_name), NULL, "no"},
- {"cacheable_dn", PW_TYPE_BOOLEAN, offsetof(ldap_instance_t, cacheable_group_dn), NULL, "no"},
+ { "name_attribute", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, groupobj_name_attr), "cn" },
+ { "membership_attribute", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, userobj_membership_attr), NULL },
+ { "membership_filter", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, groupobj_membership_filter), NULL },
+ { "cacheable_name", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, ldap_instance_t, cacheable_group_name), "no" },
+ { "cacheable_dn", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, ldap_instance_t, cacheable_group_dn), "no" },
+ { "cache_attribute", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, cache_attribute), NULL },
{ NULL, -1, 0, NULL, NULL }
};
* Client configuration
*/
static CONF_PARSER client_attribute[] = {
- {"identifier", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_identifier), NULL, "host"},
- {"shortname", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_shortname), NULL, "cn"},
- {"nas_type", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_type), NULL, NULL},
- {"secret", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_secret), NULL, NULL},
- {"virtual_server", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_server), NULL, NULL},
- {"require_message_authenticator", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_require_ma),
- NULL, NULL},
+ { "identifier", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, clientobj_identifier), "host" },
+ { "shortname", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, clientobj_shortname), "cn" },
+ { "nas_type", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, clientobj_type), NULL },
+ { "secret", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, clientobj_secret), NULL },
+ { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, clientobj_server), NULL },
+ { "require_message_authenticator", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, clientobj_require_ma), NULL },
{ NULL, -1, 0, NULL, NULL }
};
static CONF_PARSER client_config[] = {
- {"filter", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_filter), NULL, NULL},
- {"scope", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_scope_str), NULL, "sub"},
- {"base_dn", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, clientobj_base_dn), NULL, ""},
- {"attribute", PW_TYPE_SUBSECTION, 0, NULL, (void const *) client_attribute},
+ { "filter", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, clientobj_filter), NULL },
+ { "scope", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, clientobj_scope_str), "sub" },
+ { "base_dn", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, clientobj_base_dn), "" },
+ { "attribute", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) client_attribute },
{ NULL, -1, 0, NULL, NULL }
};
* Reference for accounting updates
*/
static const CONF_PARSER acct_section_config[] = {
- {"reference", PW_TYPE_STRING_PTR, offsetof(ldap_acct_section_t, reference), NULL, "."},
+ { "reference", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_acct_section_t, reference), "." },
{NULL, -1, 0, NULL, NULL}
};
/*
* Debugging flags to the server
*/
- {"ldap_debug", PW_TYPE_INTEGER, offsetof(ldap_instance_t,ldap_debug), NULL, "0x0000"},
+ { "ldap_debug", FR_CONF_OFFSET(PW_TYPE_INTEGER, ldap_instance_t, ldap_debug), "0x0000" },
- {"chase_referrals", PW_TYPE_BOOLEAN, offsetof(ldap_instance_t,chase_referrals), NULL, NULL},
+ { "chase_referrals", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, ldap_instance_t, chase_referrals), NULL },
- {"rebind", PW_TYPE_BOOLEAN, offsetof(ldap_instance_t,rebind), NULL, NULL},
+ { "rebind", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, ldap_instance_t, rebind), NULL },
/* timeout on network activity */
- {"net_timeout", PW_TYPE_INTEGER, offsetof(ldap_instance_t,net_timeout), NULL, "10"},
+ { "net_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, ldap_instance_t, net_timeout), "10" },
/* timeout for search results */
- {"res_timeout", PW_TYPE_INTEGER, offsetof(ldap_instance_t,res_timeout), NULL, "20"},
+ { "res_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, ldap_instance_t, res_timeout), "20" },
/* allow server unlimited time for search (server-side limit) */
- {"srv_timelimit", PW_TYPE_INTEGER, offsetof(ldap_instance_t,srv_timelimit), NULL, "20"},
+ { "srv_timelimit", FR_CONF_OFFSET(PW_TYPE_INTEGER, ldap_instance_t, srv_timelimit), "20" },
#ifdef LDAP_OPT_X_KEEPALIVE_IDLE
- {"idle", PW_TYPE_INTEGER, offsetof(ldap_instance_t,keepalive_idle), NULL, "60"},
+ { "idle", FR_CONF_OFFSET(PW_TYPE_INTEGER, ldap_instance_t, keepalive_idle), "60" },
#endif
#ifdef LDAP_OPT_X_KEEPALIVE_PROBES
- {"probes", PW_TYPE_INTEGER, offsetof(ldap_instance_t,keepalive_probes), NULL, "3"},
+ { "probes", FR_CONF_OFFSET(PW_TYPE_INTEGER, ldap_instance_t, keepalive_probes), "3" },
#endif
#ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL
- {"interval", PW_TYPE_INTEGER, offsetof(ldap_instance_t,keepalive_interval), NULL, "30"},
+ { "interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, ldap_instance_t, keepalive_interval), "30" },
#endif
{ NULL, -1, 0, NULL, NULL }
static const CONF_PARSER module_config[] = {
- {"server", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED, offsetof(ldap_instance_t,server), NULL, "localhost"},
- {"port", PW_TYPE_INTEGER, offsetof(ldap_instance_t,port), NULL, "389"},
+ { "server", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, ldap_instance_t, server), "localhost" },
+ { "port", FR_CONF_OFFSET(PW_TYPE_SHORT, ldap_instance_t, port), "389" },
- {"password", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t,password), NULL, ""},
- {"identity", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t,admin_dn), NULL, ""},
+ { "password", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, ldap_instance_t, password), "" },
+ { "identity", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, admin_dn), "" },
- {"valuepair_attribute", PW_TYPE_STRING_PTR, offsetof(ldap_instance_t, valuepair_attr), NULL, NULL},
+ { "valuepair_attribute", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_instance_t, valuepair_attr), NULL },
#ifdef WITH_EDIR
/* support for eDirectory Universal Password */
- {"edir", PW_TYPE_BOOLEAN, offsetof(ldap_instance_t,edir), NULL, NULL}, /* NULL defaults to "no" */
+ { "edir", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, ldap_instance_t, edir), NULL }, /* NULL defaults to "no" */
/*
- * Attempt to bind with the Cleartext password we got from eDirectory
+ * Attempt to bind with the cleartext password we got from eDirectory
* Universal password for additional authorization checks.
*/
- {"edir_autz", PW_TYPE_BOOLEAN, offsetof(ldap_instance_t,edir_autz), NULL, NULL}, /* NULL defaults to "no" */
+ { "edir_autz", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, ldap_instance_t, edir_autz), NULL }, /* NULL defaults to "no" */
#endif
- {"read_clients", PW_TYPE_BOOLEAN, offsetof(ldap_instance_t,do_clients), NULL, NULL}, /* NULL defaults to "no" */
+ { "read_clients", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, ldap_instance_t, do_clients), NULL }, /* NULL defaults to "no" */
- { "user", PW_TYPE_SUBSECTION, 0, NULL, (void const *) user_config },
+ { "user", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) user_config },
- { "group", PW_TYPE_SUBSECTION, 0, NULL, (void const *) group_config },
+ { "group", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) group_config },
- { "client", PW_TYPE_SUBSECTION, 0, NULL, (void const *) client_config },
+ { "client", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) client_config },
- { "profile", PW_TYPE_SUBSECTION, 0, NULL, (void const *) profile_config },
+ { "profile", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) profile_config },
- { "options", PW_TYPE_SUBSECTION, 0, NULL, (void const *) option_config },
+ { "options", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) option_config },
- { "tls", PW_TYPE_SUBSECTION, 0, NULL, (void const *) tls_config },
+ { "tls", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) tls_config },
{NULL, -1, 0, NULL, NULL}
};
if (ldap_url->lud_host &&
((strncmp(inst->server, ldap_url->lud_host, strlen(inst->server)) != 0) ||
- (ldap_url->lud_port != inst->port))) {
+ ((uint32_t) ldap_url->lud_port != inst->port))) {
RDEBUG("Requested server/port is \"%s:%i\"", ldap_url->lud_host, inst->port);
goto free_urldesc;
ldap_instance_t *inst = instance;
rlm_rcode_t rcode;
- int found = false;
- int check_is_dn;
+ bool found = false;
+ bool check_is_dn;
ldap_handle_t *conn = NULL;
char const *user_dn;
* @return 0 on success, else < 0 on failure.
*/
static int parse_sub_section(ldap_instance_t *inst, CONF_SECTION *parent, ldap_acct_section_t **config,
- rlm_components_t comp)
+ rlm_components_t comp)
{
CONF_SECTION *cs;
* Group comparison checks.
*/
if (cf_section_name2(conf)) {
- ATTR_FLAGS flags;
+ static ATTR_FLAGS flags;
char buffer[256];
- snprintf(buffer, sizeof(buffer), "%s-Ldap-Group",
- inst->xlat_name);
- memset(&flags, 0, sizeof(flags));
+ snprintf(buffer, sizeof(buffer), "%s-Ldap-Group", inst->xlat_name);
+ if (dict_addattr(buffer, -1, 0, PW_TYPE_STRING, flags) < 0) {
+ LDAP_ERR("Error creating group attribute: %s", fr_strerror());
- dict_addattr(buffer, -1, 0, PW_TYPE_STRING, flags);
+ return -1;
+ }
inst->group_da = dict_attrbyname(buffer);
if (!inst->group_da) {
LDAP_ERR("Failed creating attribute %s", buffer);
xlat_register(inst->xlat_name, ldap_xlat, rlm_ldap_escape_func, inst);
/*
+ * Setup the cache attribute
+ */
+ if (inst->cache_attribute) {
+ static ATTR_FLAGS flags;
+
+ if (dict_addattr(inst->cache_attribute, -1, 0, PW_TYPE_STRING, flags) < 0) {
+ LDAP_ERR("Error creating cache attribute: %s", fr_strerror());
+
+ return -1;
+ }
+ inst->cache_da = dict_attrbyname(inst->cache_attribute);
+ } else {
+ inst->cache_da = inst->group_da; /* Default to the group_da */
+ }
+
+ /*
* Initialize the socket pool.
*/
inst->pool = fr_connection_pool_init(inst->cs, inst, mod_conn_create, NULL, mod_conn_delete, NULL);
return -1;
}
-/** Check the user's password against ldap directory
- *
- * @param instance rlm_ldap configuration.
- * @param request Current request.
- * @return one of the RLM_MODULE_* values.
- */
-static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
{
rlm_rcode_t rcode;
ldap_rcode_t status;
if (!request->password ||
(request->password->da->attr != PW_USER_PASSWORD)) {
- RWDEBUG("You have set \"Auth-Type := LDAP\" somewhere.");
+ RWDEBUG("You have set \"Auth-Type := LDAP\" somewhere");
RWDEBUG("*********************************************");
RWDEBUG("* THAT CONFIGURATION IS WRONG. DELETE IT. ");
- RWDEBUG("* YOU ARE PREVENTING THE SERVER FROM WORKING.");
+ RWDEBUG("* YOU ARE PREVENTING THE SERVER FROM WORKING");
RWDEBUG("*********************************************");
- REDEBUG("Attribute \"User-Password\" is required for authentication.");
+ REDEBUG("Attribute \"User-Password\" is required for authentication");
return RLM_MODULE_INVALID;
}
return rcode;
}
-/** Check if user is authorized for remote access
- *
- */
-static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
{
rlm_rcode_t rcode = RLM_MODULE_OK;
ldap_rcode_t status;
rlm_ldap_map_xlat_t expanded; /* faster than mallocing every time */
if (!request->username) {
- RDEBUG2("Attribute \"User-Name\" is required for authorization.");
+ RDEBUG2("Attribute \"User-Name\" is required for authorization");
return RLM_MODULE_NOOP;
}
pairstrcpy(vp, password);
vp->length = pass_size;
- RDEBUG2("Added eDirectory password. control:%s += '%s'", vp->da->name, vp->vp_strvalue);
+ if (RDEBUG_ENABLED3) {
+ RDEBUG3("Added eDirectory password. control:%s += '%s'", vp->da->name, vp->vp_strvalue);
+ } else {
+ RDEBUG2("Added eDirectory password");
+ }
+
if (inst->edir_autz) {
RDEBUG2("Binding as user for eDirectory authorization checks");
/*
* Iterate over all the pairs, building our mods array
*/
for (ci = cf_item_find_next(cs, NULL); ci != NULL; ci = cf_item_find_next(cs, ci)) {
- int do_xlat = false;
+ bool do_xlat = false;
- if (total == LDAP_MAX_ATTRMAP) {
- REDEBUG("Modify map size exceeded");
+ if (total == LDAP_MAX_ATTRMAP) {
+ REDEBUG("Modify map size exceeded");
- goto error;
- }
+ goto error;
+ }
if (!cf_item_is_pair(ci)) {
REDEBUG("Entry is not in \"ldap-attribute = value\" format");
} else if (do_xlat) {
char *exp = NULL;
- if (radius_xlat(exp, 0, request, value, NULL, NULL) <= 0) {
+ if (radius_axlat(&exp, request, value, NULL, NULL) <= 0) {
RDEBUG("Skipping attribute \"%s\"", attr);
talloc_free(exp);
#endif
default:
REDEBUG("Operator '%s' is not supported for LDAP modify operations",
- fr_int2str(fr_tokens, op, "<INVALID>"));
+ fr_int2str(fr_tokens, op, "<INVALID>"));
goto error;
}
return rcode;
}
-static rlm_rcode_t mod_accounting(void *instance, REQUEST * request) {
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST * request) {
ldap_instance_t *inst = instance;
if (inst->accounting) {
return RLM_MODULE_NOOP;
}
-static rlm_rcode_t mod_post_auth(void *instance, REQUEST * request)
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST * request)
{
ldap_instance_t *inst = instance;
*/
typedef struct rlm_linelog_t {
CONF_SECTION *cs;
- char *filename;
- char *syslog_facility;
+ char const *filename;
+ char const *syslog_facility;
int facility;
- int permissions;
- char *group;
- char *line;
- char *reference;
+ uint32_t permissions;
+ char const *group;
+ char const *line;
+ char const *reference;
+ fr_logfile_t *lf;
} rlm_linelog_t;
/*
* buffer over-flows.
*/
static const CONF_PARSER module_config[] = {
- { "filename", PW_TYPE_FILE_OUTPUT| PW_TYPE_REQUIRED,
- offsetof(rlm_linelog_t,filename), NULL, NULL},
- { "syslog_facility", PW_TYPE_STRING_PTR,
- offsetof(rlm_linelog_t,syslog_facility), NULL, NULL},
- { "permissions", PW_TYPE_INTEGER,
- offsetof(rlm_linelog_t,permissions), NULL, "0600"},
- { "group", PW_TYPE_STRING_PTR,
- offsetof(rlm_linelog_t,group), NULL, NULL},
- { "format", PW_TYPE_STRING_PTR,
- offsetof(rlm_linelog_t,line), NULL, NULL},
- { "reference", PW_TYPE_STRING_PTR,
- offsetof(rlm_linelog_t,reference), NULL, NULL},
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT| PW_TYPE_REQUIRED, rlm_linelog_t, filename), NULL },
+ { "syslog_facility", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_linelog_t, syslog_facility), NULL },
+ { "permissions", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_linelog_t, permissions), "0600" },
+ { "group", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_linelog_t, group), NULL },
+ { "format", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_linelog_t, line), NULL },
+ { "reference", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_linelog_t, reference), NULL },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
{
rlm_linelog_t *inst = instance;
- rad_assert(inst->filename && *inst->filename);
+ if (!inst->filename) {
+ cf_log_err_cs(conf, "No value provided for 'filename'");
+ return -1;
+ }
#ifndef HAVE_SYSLOG_H
if (strcmp(inst->filename, "syslog") == 0) {
return -1;
}
+ inst->lf = fr_logfile_init(inst);
+ if (!inst->lf) {
+ cf_log_err_cs(conf, "Failed creating log file context");
+ return -1;
+ }
+
inst->cs = conf;
return 0;
}
default:
if (outlen <= 4) break;
- snprintf(out, outlen, "\\%03o", *in);
+ snprintf(out, outlen, "\\%03o", (uint8_t) *in);
in++;
out += 4;
outlen -= 4;
return len;
}
-static rlm_rcode_t do_linelog(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_do_linelog(void *instance, REQUEST *request)
{
int fd = -1;
char buffer[4096];
char *endptr;
#endif
+ line[0] = '\0';
+
if (inst->reference) {
CONF_ITEM *ci;
CONF_PAIR *cp;
p = line + 1;
- if (radius_xlat(p, sizeof(line) - 2, request, inst->reference, linelog_escape_func,
- NULL) < 0) {
+ if (radius_xlat(p, sizeof(line) - 2, request, inst->reference, linelog_escape_func, NULL) < 0) {
return RLM_MODULE_FAIL;
}
if (p) {
*p = '\0';
if (rad_mkdir(buffer, 0700) < 0) {
- RERROR("rlm_linelog: Failed to create directory %s: %s", buffer, strerror(errno));
+ RERROR("rlm_linelog: Failed to create directory %s: %s", buffer, fr_syserror(errno));
return RLM_MODULE_FAIL;
}
*p = '/';
}
- fd = open(buffer, O_WRONLY | O_APPEND | O_CREAT, inst->permissions);
+ fd = fr_logfile_open(inst->lf, buffer, inst->permissions);
if (fd == -1) {
ERROR("rlm_linelog: Failed to open %s: %s",
- buffer, strerror(errno));
+ buffer, fr_syserror(errno));
return RLM_MODULE_FAIL;
}
/*
* FIXME: Check length.
*/
- if (radius_xlat(line, sizeof(line) - 1, request, value, linelog_escape_func, NULL) < 0) {
+ if (value && (radius_xlat(line, sizeof(line) - 1, request, value, linelog_escape_func, NULL) < 0)) {
if (fd > -1) {
- close(fd);
+ fr_logfile_close(inst->lf, fd);
}
return RLM_MODULE_FAIL;
strcat(line, "\n");
if (write(fd, line, strlen(line)) < 0) {
- EDEBUG("rlm_linelog: Failed writing: %s", strerror(errno));
- close(fd);
+ ERROR("rlm_linelog: Failed writing: %s", fr_syserror(errno));
+ fr_logfile_close(inst->lf, fd);
return RLM_MODULE_FAIL;
}
- close(fd);
+ fr_logfile_close(inst->lf, fd);
#ifdef HAVE_SYSLOG_H
} else {
module_t rlm_linelog = {
RLM_MODULE_INIT,
"linelog",
- RLM_TYPE_CHECK_CONFIG_SAFE, /* type */
+ RLM_TYPE_HUP_SAFE, /* type */
sizeof(rlm_linelog_t),
module_config,
mod_instantiate, /* instantiation */
NULL, /* detach */
{
- do_linelog, /* authentication */
- do_linelog, /* authorization */
- do_linelog, /* preaccounting */
- do_linelog, /* accounting */
- NULL, /* checksimul */
- do_linelog, /* pre-proxy */
- do_linelog, /* post-proxy */
- do_linelog /* post-auth */
+ mod_do_linelog, /* authentication */
+ mod_do_linelog, /* authorization */
+ mod_do_linelog, /* preaccounting */
+ mod_do_linelog, /* accounting */
+ NULL, /* checksimul */
+ mod_do_linelog, /* pre-proxy */
+ mod_do_linelog, /* post-proxy */
+ mod_do_linelog /* post-auth */
#ifdef WITH_COA
- , do_linelog, /* recv-coa */
- do_linelog /* send-coa */
+ , mod_do_linelog, /* recv-coa */
+ mod_do_linelog /* send-coa */
#endif
},
};
* be used as the instance handle.
*/
typedef struct rlm_logintime_t {
- int min_time;
+ uint32_t min_time;
} rlm_logintime_t;
/*
* buffer over-flows.
*/
static const CONF_PARSER module_config[] = {
- { "minimum-timeout", PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, offsetof(rlm_logintime_t,min_time), NULL, NULL},
- { "minimum_timeout", PW_TYPE_INTEGER, offsetof(rlm_logintime_t,min_time), NULL, "60" },
+ { "minimum-timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, rlm_logintime_t, min_time), NULL },
+ { "minimum_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_logintime_t, min_time), "60" },
{ NULL, -1, 0, NULL, NULL }
};
/*
* Check if account has expired, and if user may login now.
*/
-static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
{
rlm_logintime_t *inst = instance;
VALUE_PAIR *ends, *timeout;
- int left;
+ uint32_t left;
ends = pairfind(request->config_items, PW_LOGIN_TIME, 0, TAG_ANY);
if (!ends) {
timeout->vp_integer = left;
}
} else {
- timeout = radius_paircreate(request, &request->reply->vps, PW_SESSION_TIMEOUT, 0);
+ timeout = radius_paircreate(request->reply, &request->reply->vps, PW_SESSION_TIMEOUT, 0);
timeout->vp_integer = left;
}
RDEBUG("reply:Session-Timeout set to %i", left);
- return RLM_MODULE_OK;
+ return RLM_MODULE_UPDATED;
}
module_t rlm_logintime = {
RLM_MODULE_INIT,
"logintime",
- RLM_TYPE_CHECK_CONFIG_SAFE, /* type */
+ 0, /* type */
sizeof(rlm_logintime_t),
module_config,
mod_instantiate, /* instantiation */
! module supports both authorization and authentication. Authorization
sets authentication to MS-CHAP if any NTLM-related things found.
During authorization new attributes added to config_items:
- LM-Password - LM-encoded password
- NT-Password - NT-encoded password
- SMB-Account-CTRL - account control flags in SAMBA format
+ LM-Password - LM-encoded password
+ NT-Password - NT-encoded password
+ SMB-Account-CTRL - account control flags in SAMBA format
During authentication these attributes are checked against data
provided by NAS.
- RFC 2433 text with MS-CHAPv1 removed. Microsoft attributes are covered
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
CPP C preprocessor
Use these variables to override the choices made by `configure' or to help
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=membership.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
--header=FILE[:TEMPLATE]
- instantiate the configuration header FILE
+ instantiate the configuration header FILE
Configuration files:
$config_files
ssize_t len;
uint8_t ucs2_password[512];
- len = fr_utf8_to_ucs2(ucs2_password, sizeof(ucs2_password), password, strlen(password));
+ len = fr_utf8_to_ucs2(ucs2_password, sizeof(ucs2_password), password, strlen(password));
if (len < 0) {
*out = '\0';
return -1;
* For example,
* "S=0123456789ABCDEF0123456789ABCDEF01234567"
*/
- response[0] = 'S';
+ response[0] = 'S';
response[1] = '=';
/*
uint8_t const *peer_challenge, uint8_t const *auth_challenge,
char *response);
void mschap_add_reply(REQUEST *request, unsigned char ident,
- char const *name, char const *value, int len);
+ char const *name, char const *value, size_t len);
#endif /*_MSCHAP_H*/
tAttributeListRef attrListRef = 0;
char *pUserLocation = NULL;
tAttributeValueListRef valueRef = 0;
- tAttributeValueEntry *pValueEntry = NULL;
tDataList *pUserNode = NULL;
rlm_rcode_t result = RLM_MODULE_FAIL;
for (attrIndex = 1; (attrIndex <= pRecEntry->fRecordAttributeCount) && (status == eDSNoErr); attrIndex++) {
status = dsGetAttributeEntry(nodeRef, tDataBuff, attrListRef, attrIndex, &valueRef, &pAttrEntry);
if (status == eDSNoErr && pAttrEntry != NULL) {
+ tAttributeValueEntry *pValueEntry = NULL;
+
if (strcmp(pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation) == 0) {
status = dsGetAttributeValue(nodeRef, tDataBuff, 1, valueRef, &pValueEntry);
if (status == eDSNoErr && pValueEntry != NULL) {
- pUserLocation = (char *) calloc(pValueEntry->fAttributeValueData.fBufferLength + 1, sizeof(char));
+ pUserLocation = talloc_zero_array(request, char, pValueEntry->fAttributeValueData.fBufferLength + 1);
memcpy(pUserLocation, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength);
}
} else if (strcmp(pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName) == 0) {
}
}
- if (pValueEntry != NULL) {
+ if (pValueEntry) {
dsDeallocAttributeValueEntry(dsRef, pValueEntry);
pValueEntry = NULL;
}
}
}
+ if (!pUserLocation) {
+ DEBUG2("[mschap] OpenDirectory has no user location");
+ result = RLM_MODULE_NOOP;
+ break;
+ }
+
/* OpenDirectory doesn't support mschapv2 authentication against
* Active Directory. AD users need to be authenticated using the
* normal freeradius AD path (i.e. ntlm_auth).
*/
if (strncmp(pUserLocation, kActiveDirLoc, strlen(kActiveDirLoc)) == 0) {
- DEBUG2("[mschap] OpenDirectory authentication returning noop. OD doesn't support MSCHAPv2 for ActiveDirectory users.");
+ DEBUG2("[mschap] OpenDirectory authentication returning noop. OD doesn't support MSCHAPv2 for ActiveDirectory users");
result = RLM_MODULE_NOOP;
break;
}
dsDataBufferDeAllocate(dsRef, tDataBuff);
if (pUserLocation != NULL)
- free(pUserLocation);
+ talloc_free(pUserLocation);
if (pRecName != NULL) {
dsDataListDeallocate(dsRef, pRecName);
memcpy(&(tDataBuff->fBufferData[uiCurr]), shortUserName, uiLen);
uiCurr += uiLen;
#ifndef NDEBUG
- RDEBUG2(" stepbuf server challenge:\t");
+ RINDENT();
+ RDEBUG2("Stepbuf server challenge : ");
for (t = 0; t < challenge->length; t++) {
fprintf(stderr, "%02x", challenge->vp_strvalue[t]);
}
uiCurr += uiLen;
#ifndef NDEBUG
- RDEBUG2(" stepbuf peer challenge:\t\t");
+ RDEBUG2("Stepbuf peer challenge : ");
for (t = 2; t < 18; t++) {
fprintf(stderr, "%02x", response->vp_strvalue[t]);
}
uiCurr += uiLen;
#ifndef NDEBUG
- RDEBUG2(" stepbuf p24:\t\t");
+ RDEBUG2("Stepbuf p24 : ");
+ REXDENT();
for (t = 26; t < 50; t++) {
fprintf(stderr, "%02x", response->vp_strvalue[t]);
}
pStepBuff, NULL);
if (status == eDSNoErr) {
if (pStepBuff->fBufferLength > 4) {
- uint32_t len;
+ size_t len;
memcpy(&len, pStepBuff->fBufferData, sizeof(len));
if (len == 40) {
*response->vp_strvalue,
"MS-CHAP2-Success",
mschap_reply, len+2);
- RDEBUG2("dsDoDirNodeAuth returns stepbuff: %s (len=%ld)\n", mschap_reply, len);
+ RDEBUG2("dsDoDirNodeAuth returns stepbuff: %s (len=%zu)\n", mschap_reply, len);
}
}
}
bool require_strong;
bool with_ntdomain_hack; /* this should be in another module */
char const *xlat_name;
- char *ntlm_auth;
- int ntlm_auth_timeout;
- char *ntlm_cpw;
- char *ntlm_cpw_username;
- char *ntlm_cpw_domain;
- char *local_cpw;
+ char const *ntlm_auth;
+ uint32_t ntlm_auth_timeout;
+ char const *ntlm_cpw;
+ char const *ntlm_cpw_username;
+ char const *ntlm_cpw_domain;
+ char const *local_cpw;
char const *auth_type;
bool allow_retry;
- char *retry_msg;
+ char const *retry_msg;
#ifdef WITH_OPEN_DIRECTORY
bool open_directory;
#endif
if (strncasecmp(fmt, "Challenge", 9) == 0) {
chap_challenge = pairfind(request->packet->vps, PW_MSCHAP_CHALLENGE, VENDORPEC_MICROSOFT, TAG_ANY);
if (!chap_challenge) {
- RDEBUG2("No MS-CHAP-Challenge in the request.");
- return 0;
+ REDEBUG("No MS-CHAP-Challenge in the request");
+ return -1;
}
/*
* MS-CHAP-Challenges are 8 octets,
- * for MS-CHAPv2
+ * for MS-CHAPv1
*/
if (chap_challenge->length == 8) {
- RDEBUG2(" mschap1: %02x",
- chap_challenge->vp_octets[0]);
+ RDEBUG2("mschap1: %02x", chap_challenge->vp_octets[0]);
data = chap_challenge->vp_octets;
data_len = 8;
response = pairfind(request->packet->vps, PW_MSCHAP2_RESPONSE, VENDORPEC_MICROSOFT, TAG_ANY);
if (!response) {
- RDEBUG2("MS-CHAP2-Response is required to calculate MS-CHAPv1 challenge.");
- return 0;
+ REDEBUG("MS-CHAP2-Response is required to calculate MS-CHAPv1 challenge");
+ return -1;
}
/*
* Responses are 50 octets.
*/
if (response->length < 50) {
- RAUTH("MS-CHAP-Response has the wrong format.");
- return 0;
+ REDEBUG("MS-CHAP-Response has the wrong format");
+ return -1;
}
user_name = pairfind(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
if (!user_name) {
- RDEBUG2("User-Name is required to calculate MS-CHAPv1 Challenge.");
- return 0;
+ REDEBUG("User-Name is required to calculate MS-CHAPv1 Challenge");
+ return -1;
}
- /*
+ /*
* Check for MS-CHAP-User-Name and if found, use it
* to construct the MSCHAPv1 challenge. This is
* set by rlm_eap_mschap to the MS-CHAP Response
if (inst->with_ntdomain_hack) {
username_string++;
} else {
- RDEBUG2("NT Domain delimiter found, should we have enabled with_ntdomain_hack?");
+ RWDEBUG2("NT Domain delimiter found, should we have enabled with_ntdomain_hack?");
username_string = name_attr->vp_strvalue;
}
} else {
if (response_name &&
((user_name->length != response_name->length) ||
(strncasecmp(user_name->vp_strvalue, response_name->vp_strvalue, user_name->length) != 0))) {
- RWDEBUG("User-Name (%s) is not the same as MS-CHAP Name (%s) from EAP-MSCHAPv2", user_name->vp_strvalue, response_name->vp_strvalue);
+ RWDEBUG2("User-Name (%s) is not the same as MS-CHAP Name (%s) from EAP-MSCHAPv2",
+ user_name->vp_strvalue, response_name->vp_strvalue);
}
/*
* from the MS-CHAPv2 peer challenge,
* our challenge, and the user name.
*/
- RDEBUG2("Creating challenge hash with username: %s",
- username_string);
+ RDEBUG2("Creating challenge hash with username: %s", username_string);
mschap_challenge_hash(response->vp_octets + 2,
chap_challenge->vp_octets,
username_string, buffer);
data = buffer;
data_len = 8;
} else {
- RDEBUG2("Invalid MS-CHAP challenge length");
- return 0;
+ REDEBUG("Invalid MS-CHAP challenge length");
+ return -1;
}
/*
response = pairfind(request->packet->vps, PW_MSCHAP_RESPONSE, VENDORPEC_MICROSOFT, TAG_ANY);
if (!response) response = pairfind(request->packet->vps, PW_MSCHAP2_RESPONSE, VENDORPEC_MICROSOFT, TAG_ANY);
if (!response) {
- RDEBUG2("No MS-CHAP-Response or MS-CHAP2-Response was found in the request.");
- return 0;
+ REDEBUG("No MS-CHAP-Response or MS-CHAP2-Response was found in the request");
+ return -1;
}
/*
if ((response->da->vendor == VENDORPEC_MICROSOFT) &&
(response->da->attr == PW_MSCHAP_RESPONSE) &&
((response->vp_octets[1] & 0x01) == 0)) {
- RDEBUG2("No NT-Response in MS-CHAP-Response");
- return 0;
+ REDEBUG("No NT-Response in MS-CHAP-Response");
+ return -1;
}
/*
} else if (strncasecmp(fmt, "LM-Response", 11) == 0) {
response = pairfind(request->packet->vps, PW_MSCHAP_RESPONSE, VENDORPEC_MICROSOFT, TAG_ANY);
if (!response) {
- RDEBUG2("No MS-CHAP-Response was found in the request.");
- return 0;
+ REDEBUG("No MS-CHAP-Response was found in the request");
+ return -1;
}
/*
* if the second octet says so.
*/
if ((response->vp_octets[1] & 0x01) != 0) {
- RDEBUG2("No LM-Response in MS-CHAP-Response");
- return 0;
+ REDEBUG("No LM-Response in MS-CHAP-Response");
+ return -1;
}
data = response->vp_octets + 2;
data_len = 24;
user_name = pairfind(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
if (!user_name) {
- RDEBUG2("No User-Name was found in the request.");
- return 0;
+ REDEBUG("No User-Name was found in the request");
+ return -1;
}
/*
} else {
p = strchr(user_name->vp_strvalue, '\\');
if (!p) {
- RDEBUG2("No NT-Domain was found in the User-Name.");
- return 0;
+ REDEBUG("No NT-Domain was found in the User-Name");
+ return -1;
}
/*
* Pull the User-Name out of the User-Name...
*/
} else if (strncasecmp(fmt, "User-Name", 9) == 0) {
- char const *p;
+ char const *p, *q;
user_name = pairfind(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
if (!user_name) {
- RDEBUG2("No User-Name was found in the request.");
- return 0;
+ REDEBUG("No User-Name was found in the request");
+ return -1;
}
/*
* (a la Kerberos host principal)
*/
if (strncmp(user_name->vp_strvalue, "host/", 5) == 0) {
+ p = user_name->vp_strvalue + 5;
/*
* If we're getting a User-Name formatted in this way,
* it's likely due to PEAP. When authenticating this against
* from that point to the first period into a string and appending
* a $ to the end.
*/
- p = strchr(user_name->vp_strvalue, '.');
+ q = strchr(p, '.');
/*
* use the same hack as above
* only if a period was found
*/
- if (p) {
+ if (q) {
snprintf(out, outlen, "%.*s$",
- (int) (p - user_name->vp_strvalue), user_name->vp_strvalue + 5);
+ (int) (q - p), p);
} else {
- snprintf(out, outlen, "%s$", user_name->vp_strvalue + 5);
+ snprintf(out, outlen, "%s$", p);
}
} else {
p = strchr(user_name->vp_strvalue, '\\');
}
if (mschap_ntpwdhash(buffer, buf2) < 0) {
- RERROR("Failed generating NT-Password");
+ REDEBUG("Failed generating NT-Password");
*buffer = '\0';
- return 0;
+ return -1;
}
fr_bin2hex(out, buffer, 16);
RDEBUG("LM-Hash of %s = %s", buf2, out);
return 32;
} else {
- RDEBUG2("Unknown expansion string \"%s\"",
- fmt);
- return 0;
+ REDEBUG("Unknown expansion string '%s'", fmt);
+ return -1;
}
if (outlen == 0) return 0; /* nowhere to go, don't do anything */
* Didn't set anything: this is bad.
*/
if (!data) {
- RDEBUG2("Failed to do anything intelligent");
+ RWDEBUG2("Failed to do anything intelligent");
return 0;
}
static const CONF_PARSER passchange_config[] = {
- { "ntlm_auth", PW_TYPE_STRING_PTR,
- offsetof(rlm_mschap_t, ntlm_cpw), NULL, NULL },
- { "ntlm_auth_username", PW_TYPE_STRING_PTR,
- offsetof(rlm_mschap_t, ntlm_cpw_username), NULL, NULL },
- { "ntlm_auth_domain", PW_TYPE_STRING_PTR,
- offsetof(rlm_mschap_t, ntlm_cpw_domain), NULL, NULL },
- { "local_cpw", PW_TYPE_STRING_PTR,
- offsetof(rlm_mschap_t, local_cpw), NULL, NULL },
+ { "ntlm_auth", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_mschap_t, ntlm_cpw), NULL },
+ { "ntlm_auth_username", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_mschap_t, ntlm_cpw_username), NULL },
+ { "ntlm_auth_domain", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_mschap_t, ntlm_cpw_domain), NULL },
+ { "local_cpw", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_mschap_t, local_cpw), NULL },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
static const CONF_PARSER module_config[] = {
/*
* Cache the password by default.
*/
- { "use_mppe", PW_TYPE_BOOLEAN,
- offsetof(rlm_mschap_t,use_mppe), NULL, "yes" },
- { "require_encryption", PW_TYPE_BOOLEAN,
- offsetof(rlm_mschap_t,require_encryption), NULL, "no" },
- { "require_strong", PW_TYPE_BOOLEAN,
- offsetof(rlm_mschap_t,require_strong), NULL, "no" },
- { "with_ntdomain_hack", PW_TYPE_BOOLEAN,
- offsetof(rlm_mschap_t,with_ntdomain_hack), NULL, "yes" },
- { "ntlm_auth", PW_TYPE_STRING_PTR,
- offsetof(rlm_mschap_t, ntlm_auth), NULL, NULL },
- { "ntlm_auth_timeout", PW_TYPE_INTEGER,
- offsetof(rlm_mschap_t, ntlm_auth_timeout), NULL, NULL },
- { "passchange", PW_TYPE_SUBSECTION, 0, NULL, (void const *) passchange_config },
- { "allow_retry", PW_TYPE_BOOLEAN,
- offsetof(rlm_mschap_t, allow_retry), NULL, "yes" },
- { "retry_msg", PW_TYPE_STRING_PTR,
- offsetof(rlm_mschap_t, retry_msg), NULL, NULL },
+ { "use_mppe", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_mschap_t, use_mppe), "yes" },
+ { "require_encryption", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_mschap_t, require_encryption), "no" },
+ { "require_strong", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_mschap_t, require_strong), "no" },
+ { "with_ntdomain_hack", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_mschap_t, with_ntdomain_hack), "yes" },
+ { "ntlm_auth", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_mschap_t, ntlm_auth), NULL },
+ { "ntlm_auth_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_mschap_t, ntlm_auth_timeout), NULL },
+ { "passchange", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) passchange_config },
+ { "allow_retry", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_mschap_t, allow_retry), "yes" },
+ { "retry_msg", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_mschap_t, retry_msg), NULL },
#ifdef WITH_OPEN_DIRECTORY
- { "use_open_directory", PW_TYPE_BOOLEAN,
- offsetof(rlm_mschap_t,open_directory), NULL, "yes" },
+ { "use_open_directory", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_mschap_t, open_directory), "yes" },
#endif
{ NULL, -1, 0, NULL, NULL } /* end the list */
* attribute to reply packet
*/
void mschap_add_reply(REQUEST *request, unsigned char ident,
- char const* name, char const* value, int len)
+ char const *name, char const *value, size_t len)
{
VALUE_PAIR *vp;
- uint8_t *p;
vp = pairmake_reply(name, NULL, T_OP_EQ);
if (!vp) {
- RDEBUG("Failed to create attribute %s: %s\n", name, fr_strerror());
+ REDEBUG("Failed to create attribute %s: %s", name, fr_strerror());
return;
}
+
+ /* Account for the ident byte */
vp->length = len + 1;
- vp->vp_octets = p = talloc_array(vp, uint8_t, vp->length);
+ if (vp->da->type == PW_TYPE_STRING) {
+ char *p;
+
+ vp->vp_strvalue = p = talloc_array(vp, char, vp->length + 1);
+ p[vp->length] = '\0'; /* Always \0 terminate */
+ p[0] = ident;
+ memcpy(p + 1, value, len);
+ } else {
+ uint8_t *p;
- p[0] = ident;
- memcpy(p + 1, value, len);
+ vp->vp_octets = p = talloc_array(vp, uint8_t, vp->length);
+ p[0] = ident;
+ memcpy(p + 1, value, len);
+ }
}
/*
* Add MPPE attributes to the reply.
*/
-static void mppe_add_reply(REQUEST *request,
- char const* name, uint8_t const * value, int len)
+static void mppe_add_reply(REQUEST *request, char const* name, uint8_t const * value, size_t len)
{
VALUE_PAIR *vp;
vp = pairmake_reply(name, NULL, T_OP_EQ);
if (!vp) {
- RDEBUG("rlm_mschap: mppe_add_reply failed to create attribute %s: %s\n", name, fr_strerror());
+ REDEBUG("mppe_add_reply failed to create attribute %s: %s", name, fr_strerror());
return;
}
* Perform an MS-CHAP2 password change
*/
-static int do_mschap_cpw(rlm_mschap_t *inst,
- REQUEST *request,
+static int CC_HINT(nonnull (1, 2, 4, 5)) do_mschap_cpw(rlm_mschap_t *inst,
+ REQUEST *request,
#ifdef HAVE_OPENSSL_CRYPTO_H
- VALUE_PAIR *nt_password,
+ VALUE_PAIR *nt_password,
#else
- UNUSED VALUE_PAIR *nt_password,
+ UNUSED VALUE_PAIR *nt_password,
#endif
- uint8_t *new_nt_password,
- uint8_t *old_nt_hash,
- int do_ntlm_auth)
+ uint8_t *new_nt_password,
+ uint8_t *old_nt_hash,
+ bool do_ntlm_auth)
{
if (inst->ntlm_cpw && do_ntlm_auth) {
/*
* Start up ntlm_auth with a pipe on stdin and stdout
*/
- pid = radius_start_program(inst->ntlm_cpw, request, 1, &to_child, &from_child, NULL, 0);
+ pid = radius_start_program(inst->ntlm_cpw, request, true, &to_child, &from_child, NULL, false);
if (pid < 0) {
- RDEBUG2("could not exec ntlm_auth cpw command");
+ REDEBUG("could not exec ntlm_auth cpw command");
return -1;
}
buf[len] = '\0';
if (write_all(to_child, buf, len) != len) {
- RDEBUG2("failed to write username to child");
+ REDEBUG("Failed to write username to child");
goto ntlm_auth_err;
}
} else {
- RDEBUG("No ntlm_auth username set - passchange will definitely fail!");
+ RWDEBUG2("No ntlm_auth username set, passchange will definitely fail!");
}
if (inst->ntlm_cpw_domain) {
buf[len] = '\0';
if (write_all(to_child, buf, len) != len) {
- RDEBUG2("failed to write domain to child");
+ REDEBUG("Failed to write domain to child");
goto ntlm_auth_err;
}
} else {
- RDEBUG("No ntlm_auth domain set - username must be full-username to work");
+ RWDEBUG2("No ntlm_auth domain set, username must be full-username to work");
}
/* now the password blobs */
buf[len+33] = '\0';
len = strlen(buf);
if (write_all(to_child, buf, len) != len) {
- RDEBUG2("failed to write old hash blob to child");
+ REDEBUG("Failed to write old hash blob to child");
goto ntlm_auth_err;
}
/*
- * in current samba versions, failure to supply empty
- * LM password/hash blobs causes the change to fail
+ * In current samba versions, failure to supply empty LM password/hash
+ * blobs causes the change to fail.
*/
len = sprintf(buf, "new-lm-password-blob: %01032i\n", 0);
if (write_all(to_child, buf, len) != len) {
- RDEBUG2("failed to write dummy LM password to child");
+ REDEBUG("Failed to write dummy LM password to child");
goto ntlm_auth_err;
}
len = sprintf(buf, "old-lm-hash-blob: %032i\n", 0);
if (write_all(to_child, buf, len) != len) {
- RDEBUG2("failed to write dummy LM hash to child");
+ REDEBUG("Failed to write dummy LM hash to child");
goto ntlm_auth_err;
}
if (write_all(to_child, ".\n", 2) != 2) {
- RDEBUG2("failed to send finish to child");
+ REDEBUG("Failed to send finish to child");
goto ntlm_auth_err;
}
close(to_child);
to_child = -1;
/*
- * Read from the child
+ * Read from the child
*/
len = radius_readfrom_program(request, from_child, pid, 10, buf, sizeof(buf));
if (len < 0) {
/* radius_readfrom_program will have closed from_child for us */
- RDEBUG2("Failure reading from child");
+ REDEBUG("Failure reading from child");
return -1;
}
close(from_child);
child_pid = rad_waitpid(pid, &status);
if (child_pid == 0) {
- RDEBUG2("Timeout waiting for child");
+ REDEBUG("Timeout waiting for child");
return -1;
}
if (child_pid != pid) {
- RDEBUG("Abnormal exit status: %s", strerror(errno));
+ REDEBUG("Abnormal exit status: %s", fr_syserror(errno));
return -1;
}
} else {
emsg = "could not find error";
}
- RDEBUG2("ntlm auth password change failed: %s", emsg);
+ REDEBUG("ntlm auth password change failed: %s", emsg);
ntlm_auth_err:
/* safe because these either need closing or are == -1 */
} else if (inst->local_cpw) {
#ifdef HAVE_OPENSSL_CRYPTO_H
/*
- * decrypt the new password blob, add it as a temporary request
- * variable, xlat the local_cpw string, then remove it
+ * Decrypt the new password blob, add it as a temporary request
+ * variable, xlat the local_cpw string, then remove it
*
- * this allows is to write e..g
+ * this allows is to write e..g
*
- * %{sql:insert into ...}
+ * %{sql:insert into ...}
*
- * ...or...
+ * ...or...
*
- * %{exec:/path/to %{mschap:User-Name} %{MS-CHAP-New-Password}}"
+ * %{exec:/path/to %{mschap:User-Name} %{MS-CHAP-New-Password}}"
*
*/
-
VALUE_PAIR *new_pass, *new_hash;
uint8_t *p, *q;
char *x;
}
/*
- * decrypt the blob
+ * Decrypt the blob
*/
RC4_set_key(&key, nt_password->length, nt_password->vp_octets);
RC4(&key, 516, new_nt_password, nt_pass_decrypted);
/*
- * pwblock is
- * 512-N bytes random pad
- * N bytes password as utf-16-le
- * 4 bytes - N as big-endian int
+ * pwblock is
+ * 512-N bytes random pad
+ * N bytes password as utf-16-le
+ * 4 bytes - N as big-endian int
*/
-
passlen = nt_pass_decrypted[512];
passlen += nt_pass_decrypted[513] << 8;
if ((nt_pass_decrypted[514] != 0) ||
(nt_pass_decrypted[515] != 0)) {
- RDEBUG2("Decrypted new password blob claims length > 65536 - probably an invalid NT-Password");
+ REDEBUG("Decrypted new password blob claims length > 65536, "
+ "probably an invalid NT-Password");
return -1;
}
/*
- * sanity check - passlen positive and <= 512
- * if not, crypto has probably gone wrong
+ * Sanity check - passlen positive and <= 512 if not, crypto has probably gone wrong
*/
if (passlen > 512) {
- RDEBUG2("Decrypted new password blob claims length %u > 512 - probably an invalid NT-Password", passlen);
+ REDEBUG("Decrypted new password blob claims length %zu > 512, "
+ "probably an invalid NT-Password", passlen);
return -1;
}
p = nt_pass_decrypted + 512 - passlen;
/*
- * the new NT hash - this should be preferred over the
- * cleartext password as it avoids unicode hassles
+ * The new NT hash - this should be preferred over the
+ * cleartext password as it avoids unicode hassles.
*/
new_hash = pairmake_packet("MS-CHAP-New-NT-Password", NULL,
T_OP_EQ);
fr_md4_calc(q, p, passlen);
/*
- * check that nt_password encrypted with new_hash
- * matches the old_hash value from the client
+ * Check that nt_password encrypted with new_hash
+ * matches the old_hash value from the client.
*/
smbhash(old_nt_hash_expected, nt_password->vp_octets, q);
smbhash(old_nt_hash_expected+8, nt_password->vp_octets+8, q + 7);
if (memcmp(old_nt_hash_expected, old_nt_hash, 16)!=0) {
- RDEBUG2("old NT hash value from client does not match our value");
+ REDEBUG("Old NT hash value from client does not match our value");
return -1;
}
/*
- * the new cleartext password, which is utf-16
- * do some unpleasant vileness to turn it into
- * utf8 without pulling in libraries like iconv
+ * The new cleartext password, which is utf-16 do some unpleasant vileness
+ * to turn it into utf8 without pulling in libraries like iconv.
*/
- new_pass = pairmake_packet("MS-CHAP-New-Cleartext-Password", NULL,
- T_OP_EQ);
+ new_pass = pairmake_packet("MS-CHAP-New-Cleartext-Password", NULL, T_OP_EQ);
new_pass->length = 0;
new_pass->vp_strvalue = x = talloc_array(new_pass, char, 254);
i = 0;
while (i<passlen) {
/*
- * The client-supplied password is utf-16.
- * We really must perform a proper conversion
- * to utf8 here, and the same in the other direction
- * when we calculate NT-Password below, else non-ascii
- * characters will fail - I know from experience that
- * UK pound and Euro symbols are common in users
- * passwords (money obsessed!)
+ * The client-supplied password is utf-16.
+ * We really must perform a proper conversion to utf8 here,
+ * and the same in the other direction when we calculate
+ * NT-Password below, else non-ascii characters will fail -
+ * I know from experience that UK pound and Euro symbols
+ * are common in users passwords (money obsessed!)
*/
int c;
c += p[i++] << 8;
/*
- * gah. nasty. maybe we should just pull in iconv?
+ * Gah. nasty. maybe we should just pull in iconv?
*/
-
if (c < 0x7f) {
/* ascii char */
if (new_pass->length >= 253) {
- RDEBUG("Ran out of room turning new password into utf8 at %d - cleartext will be truncated!", i);
+ RWDEBUG("Ran out of room turning new password into utf8 at %zu, "
+ "cleartext will be truncated!", i);
break;
}
x[new_pass->length++] = c;
} else if (c < 0x7ff) {
/* 2-byte */
if (new_pass->length >= 252) {
- RDEBUG("Ran out of room turning new password into utf8 at %d - cleartext will be truncated!", i);
+ RWDEBUG("Ran out of room turning new password into utf8 at %zu, "
+ "cleartext will be truncated!", i);
break;
}
x[new_pass->length++] = 0xc0 + (c >> 6);
} else {
/* 3-byte */
if (new_pass->length >= 251) {
- RDEBUG("Ran out of room turning new password into utf8 at %d - cleartext will be truncated!", i);
+ RWDEBUG("Ran out of room turning new password into utf8 at %zu, "
+ "cleartext will be truncated!", i);
break;
}
x[new_pass->length++] = 0xe0 + (c >> 12);
}
}
- /*
- * perform the xlat
- */
+ /* Perform the xlat */
result_len = radius_xlat(result, sizeof(result), request, inst->local_cpw, NULL, NULL);
if (result_len < 0){
return -1;
} else if (result_len == 0) {
- RDEBUG("Local MS-CHAPv2 password change - xlat didn't give any result, assuming failure");
+ REDEBUG("Local MS-CHAPv2 password change - xlat didn't give any result, assuming failure");
return -1;
}
RDEBUG("MS-CHAPv2 password change succeeded: %s", result);
/*
- * update the NT-Password attribute with the new hash
- * this lets us fall through to the authentication
- * code using the new hash, not the old one
+ * Update the NT-Password attribute with the new hash this lets us
+ * fall through to the authentication code using the new hash,
+ * not the old one.
*/
pairmemcpy(nt_password, new_hash->vp_octets, new_hash->length);
/*
- * rock on! password change succeeded
+ * Rock on! password change succeeded.
*/
return 0;
#else
- RDEBUG("Local MS-CHAPv2 password changes require OpenSSL support");
+ REDEBUG("Local MS-CHAPv2 password changes require OpenSSL support");
return -1;
#endif
} else {
- RDEBUG("MS-CHAPv2 password change not configured");
+ REDEBUG("MS-CHAPv2 password change not configured");
}
return -1;
* authentication is in one place, and we can perhaps later replace
* it with code to call winbindd, or something similar.
*/
-static int do_mschap(rlm_mschap_t *inst,
- REQUEST *request, VALUE_PAIR *password,
- uint8_t const *challenge, uint8_t const *response,
- uint8_t *nthashhash, int do_ntlm_auth)
+static int CC_HINT(nonnull (1, 2, 4, 5 ,6)) do_mschap(rlm_mschap_t *inst, REQUEST *request, VALUE_PAIR *password,
+ uint8_t const *challenge, uint8_t const *response,
+ uint8_t *nthashhash, bool do_ntlm_auth)
{
- uint8_t calculated[24];
-
- rad_assert(request != NULL);
+ uint8_t calculated[24];
/*
* Do normal authentication.
* No password: can't do authentication.
*/
if (!password) {
- RDEBUG2("FAILED: No NT/LM-Password. Cannot perform authentication.");
+ REDEBUG("FAILED: No NT/LM-Password. Cannot perform authentication");
return -1;
}
char *p;
/*
- * look for "Password expired", or "Must
- * change password".
+ * look for "Password expired", or "Must change password".
*/
- if (strstr(buffer, "Password expired") ||
- strstr(buffer, "Must change password")) {
- RDEBUG2("ntlm_auth says %s", buffer);
+ if (strcasestr(buffer, "Password expired") ||
+ strcasestr(buffer, "Must change password")) {
+ REDEBUG2("%s", buffer);
return -648;
}
- RDEBUG2("External script failed.");
+ RDEBUG2("External script failed");
p = strchr(buffer, '\n');
if (p) *p = '\0';
- REDEBUG("External script says: %s",
- buffer);
+ REDEBUG("External script says: %s", buffer);
return -1;
}
* NT_KEY: 000102030405060708090a0b0c0d0e0f
*/
if (memcmp(buffer, "NT_KEY: ", 8) != 0) {
- RDEBUG2("Invalid output from ntlm_auth: expecting NT_KEY");
+ REDEBUG("Invalid output from ntlm_auth: expecting NT_KEY");
return -1;
}
* with an LF at the end.
*/
if (strlen(buffer + 8) < 32) {
- RDEBUG2("Invalid output from ntlm_auth: NT_KEY has unexpected length");
+ REDEBUG2("Invalid output from ntlm_auth: NT_KEY has unexpected length");
return -1;
}
* Update the NT hash hash, from the NT key.
*/
if (fr_hex2bin(nthashhash, buffer + 8, 16) != 16) {
- RDEBUG2("Invalid output from ntlm_auth: NT_KEY has non-hex values");
+ REDEBUG("Invalid output from ntlm_auth: NT_KEY has non-hex values");
return -1;
}
}
* it later. Add Auth-Type attribute if present in module
* configuration (usually Auth-Type must be "MS-CHAP")
*/
-static rlm_rcode_t mod_authorize(void * instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void * instance, REQUEST *request)
{
rlm_mschap_t *inst = instance;
VALUE_PAIR *challenge = NULL;
/*
* Set Auth-Type to MS-CHAP. The authentication code
- * will take care of turning clear-text passwords into
+ * will take care of turning cleartext passwords into
* NT/LM passwords.
*/
if (!pairmake_config("Auth-Type", inst->auth_type, T_OP_EQ)) {
* If MS-CHAP2 succeeds we MUST return
* PW_MSCHAP2_SUCCESS
*/
-static rlm_rcode_t mod_authenticate(void * instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void * instance, REQUEST *request)
{
#define inst ((rlm_mschap_t *)instance)
VALUE_PAIR *challenge = NULL;
uint8_t *p;
char const *username_string;
int chap = 0;
- int do_ntlm_auth;
+ bool do_ntlm_auth;
/*
* If we have ntlm_auth configured, use it unless told
*/
if (do_ntlm_auth) {
VALUE_PAIR *vp = pairfind(request->config_items, PW_MS_CHAP_USE_NTLM_AUTH, 0, TAG_ANY);
- if (vp) do_ntlm_auth = vp->vp_integer;
+ if (vp) do_ntlm_auth = (vp->vp_integer > 0);
}
/*
if (!smb_ctrl) {
password = pairfind(request->config_items, PW_SMB_ACCOUNT_CTRL_TEXT, 0, TAG_ANY);
if (password) {
- smb_ctrl = pairmake_config("SMB-Account-CTRL", "0",
- T_OP_SET);
+ smb_ctrl = pairmake_config("SMB-Account-CTRL", "0", T_OP_SET);
if (smb_ctrl) {
smb_ctrl->vp_integer = pdb_decode_acct_ctrl(password->vp_strvalue);
}
* Password is not required.
*/
if ((smb_ctrl->vp_integer & ACB_PWNOTREQ) != 0) {
- RDEBUG2("SMB-Account-Ctrl says no password is required.");
+ RDEBUG2("SMB-Account-Ctrl says no password is required");
return RLM_MODULE_OK;
}
}
if (lm_password->length == 16) {
RDEBUG2("Found LM-Password");
} else {
- RERROR("LM-Password has not been normalized by the \"pap\" module. Authentication will fail.");
+ RWDEBUG("LM-Password has not been normalized by the 'pap' module. Authentication will fail");
lm_password = NULL;
}
/*
smbdes_lmpwdhash(password->vp_strvalue, p);
}
} else if (!do_ntlm_auth) {
- RDEBUG2("No Cleartext-Password configured. Cannot create LM-Password");
+ RWDEBUG2("No Cleartext-Password configured. Cannot create LM-Password");
}
/*
if (nt_password->length == 16) {
RDEBUG2("Found NT-Password");
} else {
- RERROR("NT-Password has not been normalized by the \"pap\" module. Authentication will fail.");
+ RWDEBUG("NT-Password has not been normalized by the 'pap' module. Authentication will fail");
nt_password = NULL;
}
/*
return RLM_MODULE_FAIL;
}
} else if (!do_ntlm_auth) {
- RDEBUG2("No Cleartext-Password configured. Cannot create NT-Password");
+ RWDEBUG2("No Cleartext-Password configured. Cannot create NT-Password");
}
cpw = pairfind(request->packet->vps, PW_MSCHAP2_CPW, VENDORPEC_MICROSOFT, TAG_ANY);
RDEBUG("MS-CHAPv2 password change request received");
if (cpw->length != 68) {
- RDEBUG2("MS-CHAP2-CPW has the wrong format - length %d!=68", cpw->length);
+ REDEBUG("MS-CHAP2-CPW has the wrong format: length %zu != 68", cpw->length);
return RLM_MODULE_INVALID;
} else if (cpw->vp_octets[0]!=7) {
- RDEBUG2("MS-CHAP2-CPW has the wrong format - code %d!=7", cpw->vp_octets[0]);
+ REDEBUG("MS-CHAP2-CPW has the wrong format: code %d != 7", cpw->vp_octets[0]);
return RLM_MODULE_INVALID;
}
/*
- * look for the new (encrypted) password
- * bah stupid composite attributes
- * we're expecting 3 attributes with the leading bytes
- * 06:<mschapid>:00:01:<1st chunk>
- * 06:<mschapid>:00:02:<2nd chunk>
- * 06:<mschapid>:00:03:<3rd chunk>
+ * look for the new (encrypted) password
+ * bah stupid composite attributes
+ * we're expecting 3 attributes with the leading bytes
+ * 06:<mschapid>:00:01:<1st chunk>
+ * 06:<mschapid>:00:02:<2nd chunk>
+ * 06:<mschapid>:00:03:<3rd chunk>
*/
for (seq = 1; seq < 4; seq++) {
vp_cursor_t cursor;
int found = 0;
- for (nt_enc = paircursor(&cursor, &request->packet->vps);
+ for (nt_enc = fr_cursor_init(&cursor, &request->packet->vps);
nt_enc;
- nt_enc = pairnext(&cursor)) {
+ nt_enc = fr_cursor_next(&cursor)) {
if (nt_enc->da->vendor != VENDORPEC_MICROSOFT)
continue;
continue;
if (nt_enc->vp_octets[0] != 6) {
- RDEBUG2("MS-CHAP-NT-Enc-PW with invalid format");
+ REDEBUG("MS-CHAP-NT-Enc-PW with invalid format");
return RLM_MODULE_INVALID;
}
if (nt_enc->vp_octets[2]==0 && nt_enc->vp_octets[3]==seq) {
}
if (!found) {
- RDEBUG2("Could not find MS-CHAP-NT-Enc-PW w/ sequence number %d", seq);
+ REDEBUG("Could not find MS-CHAP-NT-Enc-PW w/ sequence number %d", seq);
return RLM_MODULE_INVALID;
}
new_nt_enc_len += nt_enc->length - 4;
}
if (new_nt_enc_len != 516) {
- RDEBUG2("Unpacked MS-CHAP-NT-Enc-PW length != 516");
+ REDEBUG("Unpacked MS-CHAP-NT-Enc-PW length != 516");
return RLM_MODULE_INVALID;
}
* 2 octets - flags (ignored)
*/
- memcpy(old_nt_encrypted, cpw->vp_octets+2, sizeof(old_nt_encrypted));
+ memcpy(old_nt_encrypted, cpw->vp_octets + 2, sizeof(old_nt_encrypted));
RDEBUG2("Password change payload valid");
/* perform the actual password change */
+ rad_assert(nt_password);
if (do_mschap_cpw(inst, request, nt_password, new_nt_encrypted, old_nt_encrypted, do_ntlm_auth) < 0) {
char buffer[128];
- RDEBUG("Password change failed");
+ REDEBUG("Password change failed");
snprintf(buffer, sizeof(buffer), "E=709 R=0 M=Password change failed");
mschap_add_reply(request, cpw->vp_octets[1], "MS-CHAP-Error", buffer, strlen(buffer));
RDEBUG("Password change successful");
/*
- * Clear any expiry bit so the user can now login;
- * obviously the password change action will need
- * to have cleared this bit in the config/SQL/wherever
+ * Clear any expiry bit so the user can now login;
+ * obviously the password change action will need
+ * to have cleared this bit in the config/SQL/wherever
*/
if (smb_ctrl && smb_ctrl->vp_integer & ACB_PW_EXPIRED) {
- RDEBUG("clearing expiry bit in SMB-Acct-Ctrl to allow authentication");
+ RDEBUG("Clearing expiry bit in SMB-Acct-Ctrl to allow authentication");
smb_ctrl->vp_integer &= ~ACB_PW_EXPIRED;
}
/*
- * extract the challenge & response from the end of the password
- * change, add them into the request and then continue with
- * the authentication
+ * Extract the challenge & response from the end of the password
+ * change, add them into the request and then continue with
+ * the authentication
*/
- response = radius_paircreate(request, &request->packet->vps,
+ response = radius_paircreate(request->packet, &request->packet->vps,
PW_MSCHAP2_RESPONSE,
VENDORPEC_MICROSOFT);
response->length = 50;
* MS-CHAPv1 challenges are 8 octets.
*/
if (challenge->length < 8) {
- RAUTH("MS-CHAP-Challenge has the wrong format.");
+ REDEBUG("MS-CHAP-Challenge has the wrong format");
return RLM_MODULE_INVALID;
}
* Responses are 50 octets.
*/
if (response->length < 50) {
- RAUTH("MS-CHAP-Response has the wrong format.");
+ REDEBUG("MS-CHAP-Response has the wrong format");
return RLM_MODULE_INVALID;
}
*/
if (do_mschap(inst, request, password, challenge->vp_octets, response->vp_octets + offset, nthashhash,
do_ntlm_auth) < 0) {
- RDEBUG2("MS-CHAP-Response is incorrect.");
+ REDEBUG("MS-CHAP-Response is incorrect");
goto do_error;
}
* MS-CHAPv2 challenges are 16 octets.
*/
if (challenge->length < 16) {
- RAUTH("MS-CHAP-Challenge has the wrong format.");
+ REDEBUG("MS-CHAP-Challenge has the wrong format");
return RLM_MODULE_INVALID;
}
* Responses are 50 octets.
*/
if (response->length < 50) {
- RAUTH("MS-CHAP-Response has the wrong format.");
+ REDEBUG("MS-CHAP-Response has the wrong format");
return RLM_MODULE_INVALID;
}
*/
username = pairfind(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
if (!username) {
- RAUTH("We require a User-Name for MS-CHAPv2");
+ REDEBUG("We require a User-Name for MS-CHAPv2");
return RLM_MODULE_INVALID;
}
if (inst->with_ntdomain_hack) {
username_string++;
} else {
- RDEBUG2("NT Domain delimeter found, should we have enabled with_ntdomain_hack?");
+ RWDEBUG2("NT Domain delimeter found, should with_ntdomain_hack of been enabled?");
username_string = name_attr->vp_strvalue;
}
} else {
* Otherwise OD will determine auth success/fail.
*/
if (!nt_password && inst->open_directory) {
- RDEBUG2("No NT-Password configured. Trying OpenDirectory Authentication.");
+ RDEBUG2("No NT-Password configured. Trying OpenDirectory Authentication");
int odStatus = od_mschap_auth(request, challenge, username);
if (odStatus != RLM_MODULE_NOOP) {
return odStatus;
username_string, /* user name */
mschapv1_challenge); /* resulting challenge */
- RDEBUG2("Client is using MS-CHAPv2 for %s, we need NT-Password", username_string);
+ RDEBUG2("Client is using MS-CHAPv2");
mschap_result = do_mschap(inst, request, nt_password, mschapv1_challenge,
response->vp_octets + 26, nthashhash, do_ntlm_auth);
int i;
char buffer[128];
- RDEBUG2("FAILED: MS-CHAP2-Response is incorrect");
+ REDEBUG("MS-CHAP2-Response is incorrect");
do_error:
snprintf(buffer, sizeof(buffer), "E=691 R=%d", inst->allow_retry);
*/
if (((smb_ctrl->vp_integer & ACB_DISABLED) != 0) ||
((smb_ctrl->vp_integer & (ACB_NORMAL|ACB_WSTRUST)) == 0)) {
- RDEBUG2("SMB-Account-Ctrl says that the account is disabled, or is not a normal or workstation trust account");
+ REDEBUG("SMB-Account-Ctrl says that the account is disabled, or is not a normal "
+ "or workstation trust account");
mschap_add_reply(request, *response->vp_octets, "MS-CHAP-Error", "E=691 R=1", 9);
return RLM_MODULE_NOTFOUND;
}
* User is locked out.
*/
if ((smb_ctrl->vp_integer & ACB_AUTOLOCK) != 0) {
- RDEBUG2("SMB-Account-Ctrl says that the account is locked out");
+ REDEBUG("SMB-Account-Ctrl says that the account is locked out");
mschap_add_reply(request, *response->vp_octets, "MS-CHAP-Error", "E=647 R=0", 9);
return RLM_MODULE_USERLOCK;
}
memcpy(mppe_sendkey + 8, nthashhash, 16);
mppe_add_reply(request, "MS-CHAP-MPPE-Keys", mppe_sendkey, 32);
} else if (chap == 2) {
- RDEBUG2("adding MS-CHAPv2 MPPE keys");
+ RDEBUG2("Adding MS-CHAPv2 MPPE keys");
mppe_chap2_gen_keys128(nthashhash, response->vp_octets + 26, mppe_sendkey, mppe_recvkey);
- mppe_add_reply(request,
- "MS-MPPE-Recv-Key",
- mppe_recvkey, 16);
- mppe_add_reply(request,
- "MS-MPPE-Send-Key",
- mppe_sendkey, 16);
+ mppe_add_reply(request, "MS-MPPE-Recv-Key", mppe_recvkey, 16);
+ mppe_add_reply(request, "MS-MPPE-Send-Key", mppe_sendkey, 16);
}
pairmake_reply("MS-MPPE-Encryption-Policy",
- (inst->require_encryption)? "0x00000002":"0x00000001",
- T_OP_EQ);
+ (inst->require_encryption) ? "0x00000002":"0x00000001", T_OP_EQ);
pairmake_reply("MS-MPPE-Encryption-Types",
- (inst->require_strong)? "0x00000004":"0x00000006",
- T_OP_EQ);
+ (inst->require_strong) ? "0x00000004":"0x00000006", T_OP_EQ);
} /* else we weren't asked to use MPPE */
return RLM_MODULE_OK;
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
CPP C preprocessor
Use these variables to override the choices made by `configure' or to help
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=membership.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
* Returns: ds err
*/
-static long od_check_passwd(char const *uname, char const *password)
+static long od_check_passwd(REQUEST *request, char const *uname, char const *password)
{
long result = eDSAuthFailed;
tDirReference dsRef = 0;
status = dsGetAttributeValue( nodeRef, tDataBuff, 1, valueRef, &pValueEntry );
if ( status == eDSNoErr && pValueEntry != NULL )
{
- pUserLocation = (char *) calloc( pValueEntry->fAttributeValueData.fBufferLength + 1, sizeof(char) );
+ pUserLocation = talloc_zero_array(request, char, pValueEntry->fAttributeValueData.fBufferLength + 1);
memcpy( pUserLocation, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength );
}
}
status = dsGetAttributeValue( nodeRef, tDataBuff, 1, valueRef, &pValueEntry );
if ( status == eDSNoErr && pValueEntry != NULL )
{
- pUserName = (char *) calloc( pValueEntry->fAttributeValueData.fBufferLength + 1, sizeof(char) );
+ pUserName = talloc_zero_array(request, char, pValueEntry->fAttributeValueData.fBufferLength + 1);
memcpy( pUserName, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength );
}
}
pAuthType = dsDataNodeAllocateString( dsRef, kDSStdAuthNodeNativeClearTextOK );
uiCurr = 0;
+ if (!pUserName) {
+ RDEBUG("Failed to find user name");
+ break;
+ }
+
/* User name */
uiLen = (uint32_t)strlen( pUserName );
memcpy( &(tDataBuff->fBufferData[ uiCurr ]), &uiLen, sizeof(uiLen) );
pStepBuff = NULL;
}
if (pUserLocation != NULL) {
- free(pUserLocation);
+ talloc_free(pUserLocation);
pUserLocation = NULL;
}
+ if (pUserName != NULL) {
+ talloc_free(pUserName);
+ pUserName = NULL;
+ }
if (pRecName != NULL) {
dsDataListDeallocate( dsRef, pRecName );
free( pRecName );
* Check the users password against the standard UNIX
* password table.
*/
-static rlm_rcode_t mod_authenticate(UNUSED void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(UNUSED void *instance, REQUEST *request)
{
int ret;
long odResult = eDSAuthFailed;
return RLM_MODULE_INVALID;
}
- odResult = od_check_passwd(request->username->vp_strvalue,
+ odResult = od_check_passwd(request, request->username->vp_strvalue,
request->password->vp_strvalue);
switch(odResult) {
case eDSNoErr:
if (ret != RLM_MODULE_OK) {
RDEBUG("[%s]: Invalid password", request->username->vp_strvalue);
- return ret;
+ return ret;
}
return RLM_MODULE_OK;
/*
* member of the radius group?
*/
-static rlm_rcode_t mod_authorize(UNUSED void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, REQUEST *request)
{
struct passwd *userdata = NULL;
struct group *groupdata = NULL;
int err;
char host_ipaddr[128] = {0};
- if (!request || !request->username) {
- RDEBUG("OpenDirectory requires a User-Name attribute.");
+ if (!request->username) {
+ RDEBUG("OpenDirectory requires a User-Name attribute");
return RLM_MODULE_NOOP;
}
}
if (uuid_is_null(guid_sacl) && uuid_is_null(guid_nasgroup)) {
- RDEBUG("no access control groups, all users allowed.");
+ RDEBUG("no access control groups, all users allowed");
if (pairfind(request->config_items, PW_AUTH_TYPE, 0, TAG_ANY) == NULL) {
pairmake_config("Auth-Type", kAuthType, T_OP_EQ);
RDEBUG("Setting Auth-Type = %s", kAuthType);
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
CPP C preprocessor
Use these variables to override the choices made by `configure' or to help
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
#define OTP_CHALLENGE_PROMPT "Challenge: %{reply:OTP-Challenge}\n Response: "
typedef struct rlm_otp_t {
- char const *name; //!< Instance name for mod_authorize().
- char *otpd_rp; //!< Otpd rendezvous point.
- char *chal_prompt; //!< Text to present challenge to user
- //!< must have %s.
+ char const *name; //!< Instance name for mod_authorize().
+ char const *otpd_rp; //!< Otpd rendezvous point.
+ char const *chal_prompt; //!< Text to present challenge to user
+ //!< must have %s.
- uint8_t hmac_key[16]; //!< because it doesn't track State
+ uint8_t hmac_key[16]; //!< because it doesn't track State
- int challenge_len; //!< Challenge length, min 5 digits.
- int challenge_delay; //!< Max delay time for response, in seconds.
- int allow_sync; //!< Useful to override pwdfile
- //!< card_type settings.
- int allow_async; //!< C/R mode allowed?
+ uint32_t challenge_len; //!< Challenge length, min 5 digits.
+ uint32_t challenge_delay; //!< Max delay time for response, in seconds.
+ bool allow_sync; //!< Useful to override pwdfile
+ //!< card_type settings.
+ bool allow_async; //!< C/R mode allowed?
- int mschapv2_mppe_policy; //!< Whether or not do to mppe for
+ uint32_t mschapv2_mppe_policy; //!< Whether or not do to mppe for
//!< mschapv2.
- int mschapv2_mppe_types; //!< Key type/length for mschapv2/mppe.
- int mschap_mppe_policy; //!< Whether or not do to mppe for
+ uint32_t mschapv2_mppe_types; //!< Key type/length for mschapv2/mppe.
+ uint32_t mschap_mppe_policy; //!< Whether or not do to mppe for
//!< mschap .
- int mschap_mppe_types; //!< key type/length for mschap/mppe.
+ uint32_t mschap_mppe_types; //!< key type/length for mschap/mppe.
} rlm_otp_t;
/* otp_mppe.c */
continue;
} else {
ERROR("rlm_otp: %s: read from otpd: %s",
- __func__, strerror(errno));
+ __func__, fr_syserror(errno));
otp_putfd(fdp, 1);
return -1;
/*
* Full write with logging, and close on failure.
- * Returns 0 on success, errno on failure.
+ * Returns number of bytes written on success, errno on failure.
*/
static int otp_write(otp_fd_t *fdp, char const *buf, size_t len)
{
size_t nleft = len;
ssize_t nwrote;
- while (nleft) {
+ while (nleft) {
nwrote = write(fdp->fd, &buf[len - nleft], nleft);
if (nwrote == -1) {
if (errno == EINTR) {
continue;
} else {
ERROR("rlm_otp: %s: write to otpd: %s",
- __func__, strerror(errno));
+ __func__, fr_syserror(errno));
otp_putfd(fdp, 1);
return errno;
nleft -= nwrote;
}
- return 0;
+ return len - nleft;
}
/* connect to otpd and return fd */
fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (fd == -1) {
ERROR("rlm_otp: %s: socket: %s", __func__,
- strerror(errno));
+ fr_syserror(errno));
return -1;
}
sizeof(sa.sun_family) + sp_len) == -1) {
ERROR("rlm_otp: %s: connect(%s): %s",
- __func__, path, strerror(errno));
+ __func__, path, fr_syserror(errno));
(void) close(fd);
/* MS-CHAPv2 */
da = dict_attrbyname("MS-CHAP-Challenge");
if (da) {
- pwattr[6] = da;
+ pwattr[6] = da;
- da = dict_attrbyname("MS-CHAP2-Response");
- if (da) {
+ da = dict_attrbyname("MS-CHAP2-Response");
+ if (da) {
pwattr[7] = da;
- } else {
- pwattr[6] = NULL;
- }
+ } else {
+ pwattr[6] = NULL;
+ }
}
}
challenge[i] = '0' + rawchallenge[i] % 10;
}
- challenge[len] = '\0';
+ challenge[len] = '\0';
}
/** Guaranteed initialization
rc = pthread_mutex_init(mutexp, attr);
if (rc) {
ERROR("rlm_otp: %s: pthread_mutex_init: %s",
- caller, strerror(rc));
+ caller, fr_syserror(rc));
exit(1);
}
rc = pthread_mutex_lock(mutexp);
if (rc) {
ERROR("rlm_otp: %s: pthread_mutex_lock: %s",
- caller, strerror(rc));
+ caller, fr_syserror(rc));
exit(1);
}
rc = pthread_mutex_trylock(mutexp);
if (rc && rc != EBUSY) {
ERROR("rlm_otp: %s: pthread_mutex_trylock: %s",
- caller, strerror(rc));
+ caller, fr_syserror(rc));
exit(1);
}
int rc;
rc = pthread_mutex_unlock(mutexp);
- if (rc) {
+ if (rc) {
ERROR("rlm_otp: %s: pthread_mutex_unlock: %s",
- caller, strerror(rc));
+ caller, fr_syserror(rc));
exit(1);
- }
+ }
}
/* A mapping of configuration file names to internal variables. */
static const CONF_PARSER module_config[] = {
- { "otpd_rp", PW_TYPE_STRING_PTR, offsetof(rlm_otp_t, otpd_rp),
- NULL, OTP_OTPD_RP },
- { "challenge_prompt", PW_TYPE_STRING_PTR,offsetof(rlm_otp_t, chal_prompt),
- NULL, OTP_CHALLENGE_PROMPT },
- { "challenge_length", PW_TYPE_INTEGER, offsetof(rlm_otp_t, challenge_len),
- NULL, "6" },
- { "challenge_delay", PW_TYPE_INTEGER, offsetof(rlm_otp_t, challenge_delay),
- NULL, "30" },
- { "allow_sync", PW_TYPE_BOOLEAN, offsetof(rlm_otp_t, allow_sync),
- NULL, "yes" },
- { "allow_async", PW_TYPE_BOOLEAN, offsetof(rlm_otp_t, allow_async),
- NULL, "no" },
-
- { "mschapv2_mppe", PW_TYPE_INTEGER,
- offsetof(rlm_otp_t, mschapv2_mppe_policy), NULL, "2" },
- { "mschapv2_mppe_bits", PW_TYPE_INTEGER,
- offsetof(rlm_otp_t, mschapv2_mppe_types), NULL, "2" },
- { "mschap_mppe", PW_TYPE_INTEGER,
- offsetof(rlm_otp_t, mschap_mppe_policy), NULL, "2" },
- { "mschap_mppe_bits", PW_TYPE_INTEGER,
- offsetof(rlm_otp_t, mschap_mppe_types), NULL, "2" },
+ { "otpd_rp", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_otp_t, otpd_rp), OTP_OTPD_RP },
+ { "challenge_prompt", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_otp_t, chal_prompt), OTP_CHALLENGE_PROMPT },
+ { "challenge_length", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_otp_t, challenge_len), "6" },
+ { "challenge_delay", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_otp_t, challenge_delay), "30" },
+ { "allow_sync", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_otp_t, allow_sync), "yes" },
+ { "allow_async", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_otp_t, allow_async), "no" },
+
+ { "mschapv2_mppe", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_otp_t, mschapv2_mppe_policy), "2" },
+ { "mschapv2_mppe_bits", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_otp_t, mschapv2_mppe_types), "2" },
+ { "mschap_mppe", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_otp_t, mschap_mppe_policy), "2" },
+ { "mschap_mppe_bits", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_otp_t, mschap_mppe_types), "2" },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
(inst->challenge_len > OTP_MAX_CHALLENGE_LEN)) {
inst->challenge_len = 6;
- WDEBUG("invalid challenge_length %d, "
+ WARN("invalid challenge_length %d, "
"range 5-%d, using default of 6",
inst->challenge_len, OTP_MAX_CHALLENGE_LEN);
}
return -1;
}
- if ((inst->mschapv2_mppe_policy > 2) ||
- (inst->mschapv2_mppe_policy < 0)) {
+ if (inst->mschapv2_mppe_policy > 2) {
inst->mschapv2_mppe_policy = 2;
- WDEBUG("Invalid value for mschapv2_mppe, "
- "using default of 2");
+ WARN("Invalid value for mschapv2_mppe, using default of 2");
}
- if ((inst->mschapv2_mppe_types > 2) || (inst->mschapv2_mppe_types < 0)) {
+ if (inst->mschapv2_mppe_types > 2) {
inst->mschapv2_mppe_types = 2;
- WDEBUG("Invalid value for "
- "mschapv2_mppe_bits, using default of 2");
+ WARN("Invalid value for mschapv2_mppe_bits, using default of 2");
}
- if ((inst->mschap_mppe_policy > 2) || (inst->mschap_mppe_policy < 0)) {
+ if (inst->mschap_mppe_policy > 2) {
inst->mschap_mppe_policy = 2;
- WDEBUG("Invalid value for mschap_mppe, "
- "using default of 2");
- }
+ WARN("Invalid value for mschap_mppe, using default of 2");
+ }
if (inst->mschap_mppe_types != 2) {
inst->mschap_mppe_types = 2;
- WDEBUG("Invalid value for "
+ WARN("Invalid value for "
"mschap_mppe_bits, using default of 2");
}
/*
* Generate a challenge to be presented to the user.
*/
-static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
{
rlm_otp_t *inst = (rlm_otp_t *) instance;
auth_type_found = 0;
vp = pairfind(request->config_items, PW_AUTHTYPE, 0, TAG_ANY);
if (vp) {
- auth_type_found = 1;
- if (strcmp(vp->vp_strvalue, inst->name)) {
+ auth_type_found = 1;
+ if (strcmp(vp->vp_strvalue, inst->name)) {
return RLM_MODULE_NOOP;
- }
- }
- }
+ }
+ }
+ }
/* The State attribute will be present if this is a response. */
if (pairfind(request->packet->vps, PW_STATE, 0, TAG_ANY) != NULL) {
/* User-Name attribute required. */
if (!request->username) {
RWDEBUG("Attribute \"User-Name\" "
- "required for authentication.");
+ "required for authentication");
return RLM_MODULE_INVALID;
}
if (otp_pwe_present(request) == 0) {
RWDEBUG("Attribute "
"\"User-Password\" or equivalent required "
- "for authentication.");
+ "for authentication");
return RLM_MODULE_INVALID;
}
* Mark the packet as an Access-Challenge packet.
* The server will take care of sending it to the user.
*/
- request->reply->code = PW_ACCESS_CHALLENGE;
+ request->reply->code = PW_CODE_ACCESS_CHALLENGE;
- DEBUG("rlm_otp: Sending Access-Challenge.");
+ DEBUG("rlm_otp: Sending Access-Challenge");
if (!auth_type_found) {
pairmake_config("Auth-Type", inst->name, T_OP_EQ);
/*
* Verify the response entered by the user.
*/
-static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
{
rlm_otp_t *inst = instance;
/* User-Name attribute required. */
if (!request->username) {
RWDEBUG("Attribute \"User-Name\" required "
- "for authentication.");
+ "for authentication");
return RLM_MODULE_INVALID;
}
pwe = otp_pwe_present(request);
if (pwe == 0) {
RWDEBUG("Attribute \"User-Password\" "
- "or equivalent required for authentication.");
+ "or equivalent required for authentication");
return RLM_MODULE_INVALID;
}
* State is valid, but check expiry.
*/
then = ntohl(then);
- if (time(NULL) - then > inst->challenge_delay) {
+ if ((time(NULL) - then) > (int)inst->challenge_delay) {
REDEBUG("bad radstate for [%s]: expired",username);
return RLM_MODULE_REJECT;
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
CPP C preprocessor
Use these variables to override the choices made by `configure' or to help
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
--header=FILE[:TEMPLATE]
- instantiate the configuration header FILE
+ instantiate the configuration header FILE
Configuration files:
$config_files
} rlm_pam_t;
static const CONF_PARSER module_config[] = {
- { "pam_auth", PW_TYPE_STRING_PTR, offsetof(rlm_pam_t,pam_auth_name),
- NULL, "radiusd" },
+ { "pam_auth", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_pam_t, pam_auth_name), "radiusd" },
{ NULL, -1, 0, NULL, NULL }
};
}
/* translate between function declarations */
-static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
{
int r;
VALUE_PAIR *pair;
* a User-Name attribute.
*/
if (!request->username) {
- AUTH("rlm_pam: Attribute \"User-Name\" is required for authentication.");
+ AUTH("rlm_pam: Attribute \"User-Name\" is required for authentication");
return RLM_MODULE_INVALID;
}
* a User-Password attribute.
*/
if (!request->password) {
- AUTH("rlm_pam: Attribute \"User-Password\" is required for authentication.");
+ AUTH("rlm_pam: Attribute \"User-Password\" is required for authentication");
return RLM_MODULE_INVALID;
}
* Let the 'users' file over-ride the PAM auth name string,
* for backwards compatibility.
*/
- pair = pairfind(request->config_items, PAM_AUTH_ATTR, 0, TAG_ANY);
+ pair = pairfind(request->config_items, PW_PAM_AUTH, 0, TAG_ANY);
if (pair) pam_auth_string = pair->vp_strvalue;
r = pam_pass(request->username->vp_strvalue,
* @copyright 2001 Kostas Kalevras <kkalev@noc.ntua.gr>
*/
RCSID("$Id$")
+USES_APPLE_DEPRECATED_API
#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/modules.h>
#include <freeradius-devel/base64.h>
+#include <freeradius-devel/rad_assert.h>
#include <ctype.h>
#include "../../include/md5.h"
#include "../../include/sha1.h"
+#ifdef HAVE_OPENSSL_EVP_H
+# include <openssl/evp.h>
+#endif
+
/*
* Define a structure for our module configuration.
*
*/
typedef struct rlm_pap_t {
char const *name; /* CONF_SECTION->name, not strdup'd */
- bool auto_header;
int auth_type;
bool normify;
} rlm_pap_t;
* buffer over-flows.
*/
static const CONF_PARSER module_config[] = {
- { "auto_header", PW_TYPE_BOOLEAN, offsetof(rlm_pap_t,auto_header), NULL, "no" },
- { "normalise", PW_TYPE_BOOLEAN, offsetof(rlm_pap_t,normify), NULL, "yes" },
+ { "normalise", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_pap_t, normify), "yes" },
{ NULL, -1, 0, NULL, NULL }
};
{ "{base64_md5}", PW_MD5_PASSWORD },
{ "{smd5}", PW_SMD5_PASSWORD },
{ "{crypt}", PW_CRYPT_PASSWORD },
+#ifdef HAVE_OPENSSL_EVP_H
+ { "{sha2}", PW_SHA2_PASSWORD },
+ { "{sha256}", PW_SHA2_PASSWORD },
+ { "{sha512}", PW_SHA2_PASSWORD },
+#endif
{ "{sha}", PW_SHA_PASSWORD },
{ "{ssha}", PW_SSHA_PASSWORD },
{ "{nt}", PW_NT_PASSWORD },
/*
* Hex or base64 or bin auto-discovery.
*/
-static void normify(REQUEST *request, VALUE_PAIR *vp, size_t min_length)
+static void CC_HINT(nonnull) normify(REQUEST *request, VALUE_PAIR *vp, size_t min_length)
{
-
- uint8_t buffer[64];
+ uint8_t buffer[256];
if (min_length >= sizeof(buffer)) return; /* paranoia */
*/
if (vp->length >= (2 * min_length)) {
size_t decoded;
- decoded = fr_hex2bin(buffer, vp->vp_strvalue, vp->length >> 1);
+ decoded = fr_hex2bin(buffer, vp->vp_strvalue, sizeof(buffer));
if (decoded == (vp->length >> 1)) {
- RDEBUG2("Normalizing %s from hex encoding", vp->da->name);
+ RDEBUG2("Normalizing %s from hex encoding, %zu bytes -> %zu bytes",
+ vp->da->name, vp->length, decoded);
pairmemcpy(vp, buffer, decoded);
return;
}
*/
if ((vp->length * 3) >= ((min_length * 4))) {
ssize_t decoded;
- decoded = fr_base64_decode(vp->vp_strvalue, vp->length, buffer,
- sizeof(buffer));
+ decoded = fr_base64_decode(buffer, sizeof(buffer), vp->vp_strvalue, vp->length);
if (decoded < 0) return;
if (decoded >= (ssize_t) min_length) {
- RDEBUG2("Normalizing %s from base64 encoding", vp->da->name);
+ RDEBUG2("Normalizing %s from base64 encoding, %zu bytes -> %zu bytes",
+ vp->da->name, vp->length, decoded);
pairmemcpy(vp, buffer, decoded);
return;
}
* This isn't strictly necessary, but it does make the
* server simpler to configure.
*/
-static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
{
rlm_pap_t *inst = instance;
- int auth_type = false;
- int found_pw = false;
+ bool auth_type = false;
+ bool found_pw = false;
VALUE_PAIR *vp;
vp_cursor_t cursor;
- for (vp = paircursor(&cursor, &request->config_items);
+ for (vp = fr_cursor_init(&cursor, &request->config_items);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
switch (vp->da->attr) {
case PW_USER_PASSWORD: /* deprecated */
- RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
- RDEBUG("!!! Please update your configuration so that the \"known !!!");
- RDEBUG("!!! good\" clear text password is in Cleartext-Password, !!!");
- RDEBUG("!!! and NOT in User-Password. !!!");
- RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ RWDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ RWDEBUG("!!! Ignoring control:User-Password. Update your !!!");
+ RWDEBUG("!!! configuration so that the \"known good\" clear text !!!");
+ RWDEBUG("!!! password is in Cleartext-Password and NOT in !!!");
+ RWDEBUG("!!! User-Password. !!!");
+ RWDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
break;
case PW_PASSWORD_WITH_HEADER: /* preferred */
{
int attr;
char *p;
- char const *q;
- uint8_t *b, binbuf[128];
+ char const *data;
+ size_t length;
+ uint8_t digest[128];
char charbuf[128];
VALUE_PAIR *new_vp;
+ /*
+ * Password already exists: use
+ * that instead of this one.
+ */
+ if (pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) {
+ RWDEBUG("Config already contains \"known good\" password. "
+ "Ignoring Password-With-Header");
+ break;
+ }
+
found_pw = true;
redo:
- q = vp->vp_strvalue;
- p = strchr(q + 1, '}');
+ p = strchr(vp->vp_strvalue, '}');
if (!p) {
ssize_t decoded;
/*
- * Password already exists: use
- * that instead of this one.
- */
- if (pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) {
- RDEBUG("Config already contains \"reference\" password. Ignoring Password-With-Header");
- break;
- }
-
- /*
* If it's binary, it may be
* base64 encoded. Decode it,
* and re-write the attribute to
* have the decoded value.
*/
- decoded = fr_base64_decode(vp->vp_strvalue,
- vp->length,
- binbuf,
- sizeof(binbuf));
- if ((decoded > 0) && (binbuf[0] == '{') &&
- memchr(binbuf, '}', decoded)) {
- pairmemcpy(vp, binbuf, decoded);
+ decoded = fr_base64_decode(digest, sizeof(digest), vp->vp_strvalue, vp->length);
+ if ((decoded > 0) &&
+ (digest[0] == '{') &&
+ (memchr(digest, '}', decoded) != NULL)) {
+ RDEBUG3("Decoded %s to %d bytes",
+ vp->vp_strvalue, (int) decoded);
+ pairmemcpy(vp, digest, decoded);
goto redo;
}
- RDEBUG("Failed to decode Password-With-Header = \"%s\"", vp->vp_strvalue);
- break;
- }
+ invalid_header:
+ if (RDEBUG_ENABLED3) {
+ RDEBUG3("No {...} in Password-With-Header = \"%s\", re-writing to "
+ "Cleartext-Password", vp->vp_strvalue);
+ } else {
+ RDEBUG("No {...} in Password-With-Header, re-writing to "
+ "Cleartext-Password");
+ }
- if ((size_t) (p - q) > sizeof(charbuf)) break;
+ data = vp->vp_strvalue;
+ new_vp = radius_paircreate(request, &request->config_items,
+ PW_CLEARTEXT_PASSWORD, 0);
+ pairstrcpy(new_vp, data);
- memcpy(charbuf, q, p - q + 1);
- charbuf[p - q + 1] = '\0';
+ } else {
+ length = (p + 1) - vp->vp_strvalue;
- attr = fr_str2int(header_names, charbuf, 0);
- if (!attr) {
- RDEBUG2("Found unknown header {%s}: Not doing anything", charbuf);
- break;
- }
+ if (length >= sizeof(charbuf)) break;
- new_vp = radius_paircreate(request,
- &request->config_items,
- attr, 0);
+ memcpy(charbuf, vp->vp_strvalue, length);
+ charbuf[length] = '\0';
+
+ attr = fr_str2int(header_names, charbuf, 0);
+ if (!attr) {
+ RWDEBUG2("Found unknown header {%s}: Not doing anything", charbuf);
+ goto invalid_header;
+ }
+
+ data = vp->vp_strvalue + length;
+ length = vp->length - length;
+
+ new_vp = radius_paircreate(request, &request->config_items, attr, 0);
+
+ /*
+ * The data after the '}' may be
+ * binary, so we copy it via
+ * memcpy. BUT it might be a
+ * string, so we ensure that
+ * there's a trailing zero, too.
+ */
+ if (new_vp->da->type == PW_TYPE_OCTETS) {
+ pairmemcpy(new_vp, (uint8_t const *) data, length + 1);
+ new_vp->length = length;
+ } else {
+ pairstrcpy(new_vp, data);
+ }
+ }
- /*
- * The data after the '}' may be binary,
- * so we copy it via memcpy.
- */
- new_vp->length = vp->length;
- new_vp->length -= (p - q + 1);
- new_vp->vp_octets = b = talloc_array(new_vp, uint8_t, new_vp->length);
- memcpy(b, p + 1, new_vp->length);
}
break;
case PW_SMD5_PASSWORD:
case PW_NT_PASSWORD:
case PW_LM_PASSWORD:
- if (inst->normify)
+ if (inst->normify) {
normify(request, vp, 16); /* ensure it's in the right format */
+ }
+ found_pw = true;
+ break;
+
+#ifdef HAVE_OPENSSL_EVP_H
+ case PW_SHA2_PASSWORD:
+ if (inst->normify) {
+ normify(request, vp, 28); /* ensure it's in the right format */
+ }
found_pw = true;
break;
+#endif
case PW_SHA_PASSWORD:
case PW_SSHA_PASSWORD:
- if (inst->normify)
+ if (inst->normify) {
normify(request, vp, 20); /* ensure it's in the right format */
+ }
found_pw = true;
break;
return RLM_MODULE_NOOP;
}
- RWDEBUG("No \"known good\" password found for the user. Not setting Auth-Type.");
- RWDEBUG("Authentication will fail unless a \"known good\" password is available.");
+ RWDEBUG("No \"known good\" password found for the user. Not setting Auth-Type");
+ RWDEBUG("Authentication will fail unless a \"known good\" password is available");
return RLM_MODULE_NOOP;
}
*/
if (!request->password ||
(request->password->da->attr != PW_USER_PASSWORD)) {
- /*
- * Don't print out debugging messages if we know
- * they're useless.
- */
- if (request->packet->code == PW_ACCESS_CHALLENGE) {
- return RLM_MODULE_NOOP;
- }
-
- RDEBUG2("No clear-text password in the request. Not performing PAP.");
+ RDEBUG2("No cleartext password in the request. Not performing PAP");
return RLM_MODULE_NOOP;
}
* PAP authentication functions
*/
-static int pap_auth_clear(UNUSED rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_clear(UNUSED rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
{
- RDEBUG("Using clear text password \"%s\"", vp->vp_strvalue);
+ if (RDEBUG_ENABLED3) {
+ RDEBUG3("Comparing with \"known good\" Cleartext-Password \"%s\"", vp->vp_strvalue);
+ } else {
+ RDEBUG3("Comparing with \"known good\" Cleartext-Password");
+ }
if ((vp->length != request->password->length) ||
(rad_digest_cmp(vp->vp_octets,
request->password->vp_octets,
vp->length) != 0)) {
- REDEBUG("CLEAR TEXT password check failed");
+ REDEBUG("Cleartext password does not match \"known good\" password");
return RLM_MODULE_REJECT;
}
return RLM_MODULE_OK;
}
-static int pap_auth_crypt(UNUSED rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_crypt(UNUSED rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
{
- RDEBUG("Using CRYPT password \"%s\"", vp->vp_strvalue);
+ if (RDEBUG_ENABLED3) {
+ RDEBUG3("Comparing with \"known good\" Crypt-Password \"%s\"", vp->vp_strvalue);
+ } else {
+ RDEBUG("Comparing with \"known-good\" Crypt-password");
+ }
if (fr_crypt_check(request->password->vp_strvalue,
vp->vp_strvalue) != 0) {
- REDEBUG("CRYPT password check failed");
+ REDEBUG("Crypt digest does not match \"known good\" digest");
return RLM_MODULE_REJECT;
}
return RLM_MODULE_OK;
}
-static int pap_auth_md5(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_md5(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
{
FR_MD5_CTX md5_context;
- uint8_t binbuf[128];
+ uint8_t digest[128];
- RDEBUG("Using MD5 encryption.");
+ RDEBUG("Comparing with \"known-good\" MD5-Password");
- if (inst->normify)
+ if (inst->normify) {
normify(request, vp, 16);
+ }
if (vp->length != 16) {
- REDEBUG("Configured MD5 password has incorrect length");
- return RLM_MODULE_REJECT;
+ REDEBUG("\"known-good\" MD5 password has incorrect length");
+ return RLM_MODULE_INVALID;
}
fr_MD5Init(&md5_context);
fr_MD5Update(&md5_context, request->password->vp_octets,
request->password->length);
- fr_MD5Final(binbuf, &md5_context);
+ fr_MD5Final(digest, &md5_context);
- if (rad_digest_cmp(binbuf, vp->vp_octets, vp->length) != 0) {
- REDEBUG("MD5 password check failed");
+ if (rad_digest_cmp(digest, vp->vp_octets, vp->length) != 0) {
+ REDEBUG("MD5 digest does not match \"known good\" digest");
return RLM_MODULE_REJECT;
}
}
-static int pap_auth_smd5(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_smd5(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
{
FR_MD5_CTX md5_context;
- uint8_t binbuf[128];
+ uint8_t digest[128];
- RDEBUG("Using SMD5 encryption.");
+ RDEBUG("Comparing with \"known-good\" SMD5-Password");
- if (inst->normify)
+ if (inst->normify) {
normify(request, vp, 16);
+ }
if (vp->length <= 16) {
- REDEBUG("Configured SMD5 password has incorrect length");
- return RLM_MODULE_REJECT;
+ REDEBUG("\"known-good\" SMD5-Password has incorrect length");
+ return RLM_MODULE_INVALID;
}
fr_MD5Init(&md5_context);
fr_MD5Update(&md5_context, request->password->vp_octets,
request->password->length);
fr_MD5Update(&md5_context, &vp->vp_octets[16], vp->length - 16);
- fr_MD5Final(binbuf, &md5_context);
+ fr_MD5Final(digest, &md5_context);
/*
* Compare only the MD5 hash results, not the salt.
*/
- if (rad_digest_cmp(binbuf, vp->vp_octets, 16) != 0) {
- REDEBUG("SMD5 password check failed");
+ if (rad_digest_cmp(digest, vp->vp_octets, 16) != 0) {
+ REDEBUG("SMD5 digest does not match \"known good\" digest");
return RLM_MODULE_REJECT;
}
return RLM_MODULE_OK;
}
-static int pap_auth_sha(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_sha(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
{
fr_SHA1_CTX sha1_context;
- uint8_t binbuf[128];
+ uint8_t digest[128];
- RDEBUG("Using SHA1 encryption.");
+ RDEBUG("Comparing with \"known-good\" SHA-Password");
- if (inst->normify)
+ if (inst->normify) {
normify(request, vp, 20);
+ }
if (vp->length != 20) {
- REDEBUG("SHA1 password has incorrect length");
- return RLM_MODULE_REJECT;
+ REDEBUG("\"known-good\" SHA1-password has incorrect length");
+ return RLM_MODULE_INVALID;
}
fr_SHA1Init(&sha1_context);
fr_SHA1Update(&sha1_context, request->password->vp_octets,
request->password->length);
- fr_SHA1Final(binbuf,&sha1_context);
+ fr_SHA1Final(digest,&sha1_context);
- if (rad_digest_cmp(binbuf, vp->vp_octets, vp->length) != 0) {
- REDEBUG("SHA1 password check failed");
+ if (rad_digest_cmp(digest, vp->vp_octets, vp->length) != 0) {
+ REDEBUG("SHA1 digest does not match \"known good\" digest");
return RLM_MODULE_REJECT;
}
return RLM_MODULE_OK;
}
-static int pap_auth_ssha(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_ssha(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
{
fr_SHA1_CTX sha1_context;
- uint8_t binbuf[128];
+ uint8_t digest[128];
- RDEBUG("Using SSHA encryption.");
+ RDEBUG("Comparing with \"known-good\" SSHA-Password");
- if (inst->normify)
+ if (inst->normify) {
normify(request, vp, 20);
+ }
if (vp->length <= 20) {
- REDEBUG("SSHA password has incorrect length");
- return RLM_MODULE_REJECT;
+ REDEBUG("\"known-good\" SSHA-Password has incorrect length");
+ return RLM_MODULE_INVALID;
}
fr_SHA1Init(&sha1_context);
fr_SHA1Update(&sha1_context, request->password->vp_octets,
request->password->length);
fr_SHA1Update(&sha1_context, &vp->vp_octets[20], vp->length - 20);
- fr_SHA1Final(binbuf,&sha1_context);
+ fr_SHA1Final(digest,&sha1_context);
- if (rad_digest_cmp(binbuf, vp->vp_octets, 20) != 0) {
- REDEBUG("SSHA password check failed");
+ if (rad_digest_cmp(digest, vp->vp_octets, 20) != 0) {
+ REDEBUG("SSHA digest does not match \"known good\" digest");
return RLM_MODULE_REJECT;
}
return RLM_MODULE_OK;
}
-static int pap_auth_nt(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+#ifdef HAVE_OPENSSL_EVP_H
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_sha2(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
{
- uint8_t binbuf[16];
+ EVP_MD_CTX *ctx;
+ EVP_MD const *md;
+ char const *name;
+ uint8_t digest[EVP_MAX_MD_SIZE];
+ unsigned int digestlen;
+
+ RDEBUG("Comparing with \"known-good\" SHA2-Password");
+
+ if (inst->normify) {
+ normify(request, vp, 28);
+ }
+
+ /*
+ * All the SHA-2 algorithms produce digests of different lengths,
+ * so it's trivial to determine which EVP_MD to use.
+ */
+ switch (vp->length) {
+ /* SHA-224 */
+ case 28:
+ name = "SHA-224";
+ md = EVP_sha224();
+ break;
+
+ /* SHA-256 */
+ case 32:
+ name = "SHA-256";
+ md = EVP_sha256();
+ break;
+
+ /* SHA-384 */
+ case 48:
+ name = "SHA-384";
+ md = EVP_sha384();
+ break;
+
+ /* SHA-512 */
+ case 64:
+ name = "SHA-512";
+ md = EVP_sha512();
+ break;
+
+ default:
+ REDEBUG("\"known good\" digest length (%zu) does not match output length of any SHA-2 digests",
+ vp->length);
+ return RLM_MODULE_INVALID;
+ }
+
+ ctx = EVP_MD_CTX_create();
+ EVP_DigestInit_ex(ctx, md, NULL);
+ EVP_DigestUpdate(ctx, request->password->vp_octets, request->password->length);
+ EVP_DigestFinal_ex(ctx, digest, &digestlen);
+ EVP_MD_CTX_destroy(ctx);
+
+ fr_assert((size_t) digestlen == vp->length); /* This would be an OpenSSL bug... */
+
+ if (rad_digest_cmp(digest, vp->vp_octets, vp->length) != 0) {
+ REDEBUG("%s digest does not match \"known good\" digest", name);
+ return RLM_MODULE_REJECT;
+ }
+
+ return RLM_MODULE_OK;
+}
+#endif
+
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_nt(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+{
+ uint8_t digest[16];
char charbuf[32 + 1];
- RDEBUG("Using NT encryption.");
+ RDEBUG("Comparing with \"known-good\" NT-Password");
- if (inst->normify)
+ if (inst->normify) {
normify(request, vp, 16);
+ }
if (vp->length != 16) {
- REDEBUG("Configured NT-Password has incorrect length");
- return RLM_MODULE_REJECT;
+ REDEBUG("\"known good\" NT-Password has incorrect length");
+ return RLM_MODULE_INVALID;
}
if (radius_xlat(charbuf, sizeof(charbuf), request, "%{mschap:NT-Hash %{User-Password}}", NULL, NULL) < 0){
return RLM_MODULE_REJECT;
}
- if ((fr_hex2bin(binbuf, charbuf, sizeof(binbuf)) != vp->length) ||
- (rad_digest_cmp(binbuf, vp->vp_octets, vp->length) != 0)) {
- REDEBUG("NT password check failed");
+ if ((fr_hex2bin(digest, charbuf, sizeof(digest)) != vp->length) ||
+ (rad_digest_cmp(digest, vp->vp_octets, vp->length) != 0)) {
+ REDEBUG("NT digest does not match \"known good\" digest");
return RLM_MODULE_REJECT;
}
}
-static int pap_auth_lm(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_lm(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
{
- uint8_t binbuf[16];
+ uint8_t digest[16];
char charbuf[32 + 1];
- RDEBUG("Using LM encryption.");
+ RDEBUG("Comparing with \"known-good\" LM-Password");
- if (inst->normify)
+ if (inst->normify) {
normify(request, vp, 16);
+ }
if (vp->length != 16) {
- REDEBUG("Configure LM-Password has incorrect length");
- return RLM_MODULE_REJECT;
+ REDEBUG("\"known good\" LM-Password has incorrect length");
+ return RLM_MODULE_INVALID;
}
if (radius_xlat(charbuf, sizeof(charbuf), request, "%{mschap:LM-Hash %{User-Password}}", NULL, NULL) < 0){
- return RLM_MODULE_REJECT;
+ return RLM_MODULE_FAIL;
}
- if ((fr_hex2bin(binbuf, charbuf, sizeof(binbuf)) != vp->length) ||
- (rad_digest_cmp(binbuf, vp->vp_octets, vp->length) != 0)) {
- REDEBUG("LM password check failed");
+ if ((fr_hex2bin(digest, charbuf, sizeof(digest)) != vp->length) ||
+ (rad_digest_cmp(digest, vp->vp_octets, vp->length) != 0)) {
+ REDEBUG("LM digest does not match \"known good\" digest");
return RLM_MODULE_REJECT;
}
return RLM_MODULE_OK;
}
-static int pap_auth_ns_mta_md5(UNUSED rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_ns_mta_md5(UNUSED rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
{
FR_MD5_CTX md5_context;
- uint8_t binbuf[128];
+ uint8_t digest[128];
uint8_t buff[MAX_STRING_LEN];
char buff2[MAX_STRING_LEN + 50];
- RDEBUG("Using NT-MTA-MD5 password");
+ RDEBUG("Using NT-MTA-MD5-Password");
if (vp->length != 64) {
- REDEBUG("Configured NS-MTA-MD5-Password has incorrect length");
- return RLM_MODULE_REJECT;
+ REDEBUG("\"known good\" NS-MTA-MD5-Password has incorrect length");
+ return RLM_MODULE_INVALID;
}
/*
* Sanity check the value of NS-MTA-MD5-Password
*/
- if (fr_hex2bin(binbuf, vp->vp_strvalue, 32) != 16) {
- REDEBUG("Configured NS-MTA-MD5-Password has invalid value");
- return RLM_MODULE_REJECT;
+ if (fr_hex2bin(digest, vp->vp_strvalue, 32) != 16) {
+ REDEBUG("\"known good\" NS-MTA-MD5-Password has invalid value");
+ return RLM_MODULE_INVALID;
}
/*
* This really: sizeof(buff) - 2 - 2*32 - strlen(passwd)
*/
if (request->password->length >= (sizeof(buff) - 2 - 2 * 32)) {
- REDEBUG("Configured password is too long");
- return RLM_MODULE_REJECT;
+ REDEBUG("\"known good\" NS-MTA-MD5-Password is too long");
+ return RLM_MODULE_INVALID;
}
/*
fr_MD5Final(buff, &md5_context);
}
- if (rad_digest_cmp(binbuf, buff, 16) != 0) {
- REDEBUG("NS-MTA-MD5 password check failed");
+ if (rad_digest_cmp(digest, buff, 16) != 0) {
+ REDEBUG("NS-MTA-MD5 digest does not match \"known good\" digest");
return RLM_MODULE_REJECT;
}
/*
* Authenticate the user via one of any well-known password.
*/
-static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
{
rlm_pap_t *inst = instance;
VALUE_PAIR *vp;
rlm_rcode_t rc = RLM_MODULE_INVALID;
vp_cursor_t cursor;
- int (*auth_func)(rlm_pap_t *, REQUEST *, VALUE_PAIR *) = NULL;
-
+ rlm_rcode_t (*auth_func)(rlm_pap_t *, REQUEST *, VALUE_PAIR *) = NULL;
if (!request->password ||
(request->password->da->attr != PW_USER_PASSWORD)) {
return RLM_MODULE_INVALID;
}
- RDEBUG("login attempt with password \"%s\"", request->password->vp_strvalue);
+ if (RDEBUG_ENABLED3) {
+ RDEBUG3("Login attempt with password \"%s\"", request->password->vp_strvalue);
+ } else {
+ RDEBUG("Login attempt with password");
+ }
/*
* Auto-detect passwords, by attribute in the
* config items, to find out which authentication
* function to call.
*/
- for (vp = paircursor(&cursor, &request->config_items);
+ for (vp = fr_cursor_init(&cursor, &request->config_items);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
if (!vp->da->vendor) switch (vp->da->attr) {
case PW_CLEARTEXT_PASSWORD:
auth_func = &pap_auth_clear;
auth_func = &pap_auth_smd5;
break;
+#ifdef HAVE_OPENSSL_EVP_H
+ case PW_SHA2_PASSWORD:
+ auth_func = &pap_auth_sha2;
+ break;
+#endif
+
case PW_SHA_PASSWORD:
auth_func = &pap_auth_sha;
break;
module_t rlm_pap = {
RLM_MODULE_INIT,
"PAP",
- RLM_TYPE_CHECK_CONFIG_SAFE | RLM_TYPE_HUP_SAFE, /* type */
+ RLM_TYPE_HUP_SAFE, /* type */
sizeof(rlm_pap_t),
module_config,
mod_instantiate, /* instantiation */
/* reserve memory for (struct mypasswd) + listflag (nfields * sizeof (char*)) +
** fields (nfields * sizeof (char)) + strlen (inst->format) + 1 */
- *len=sizeof (struct mypasswd) + nfields * sizeof (char*) + nfields * sizeof (char ) + strlen(buffer) + 1;
+ *len=sizeof (struct mypasswd) + nfields * sizeof (char*) + nfields * sizeof (char ) + strlen(buffer) + 1;
t = (struct mypasswd *) rad_malloc(*len);
if (t) memset(t, 0, *len);
- return (t);
+ return (t);
}
static int string_to_entry(char const* string, int nfields, char delimiter,
if (!ht) return;
for (i = 0; i < ht->tablesize; i++)
- if (ht->table[i])
- destroy_password(ht->table[i]);
+ if (ht->table[i])
+ destroy_password(ht->table[i]);
if (ht->table) {
free(ht->table);
ht->table = NULL;
static void release_ht(struct hashtable * ht){
if (!ht) return;
release_hash_table(ht);
- if (ht->filename) free(ht->filename);
+ if (ht->filename) {
+ free(ht->filename);
+ ht->filename = NULL;
+ }
free(ht);
}
struct passwd_instance {
struct hashtable *ht;
struct mypasswd *pwdfmt;
- char *filename;
- char *format;
- char *delimiter;
+ char const *filename;
+ char const *format;
+ char const *delimiter;
bool allow_multiple;
bool ignore_nislike;
- int hash_size;
- int nfields;
- int keyfield;
- int listable;
+ uint32_t hash_size;
+ uint32_t nfields;
+ uint32_t keyfield;
+ uint32_t listable;
DICT_ATTR const *keyattr;
bool ignore_empty;
};
static const CONF_PARSER module_config[] = {
- { "filename", PW_TYPE_FILE_INPUT | PW_TYPE_REQUIRED,
- offsetof(struct passwd_instance, filename), NULL, NULL },
- { "format", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
- offsetof(struct passwd_instance, format), NULL, NULL },
- { "delimiter", PW_TYPE_STRING_PTR,
- offsetof(struct passwd_instance, delimiter), NULL, ":" },
-
- { "ignorenislike", PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED,
- offsetof(struct passwd_instance, ignore_nislike), NULL, NULL },
- { "ignore_nislike", PW_TYPE_BOOLEAN,
- offsetof(struct passwd_instance, ignore_nislike), NULL, "yes" },
-
- { "ignoreempty", PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED,
- offsetof(struct passwd_instance, ignore_empty), NULL, NULL },
- { "ignore_empty", PW_TYPE_BOOLEAN,
- offsetof(struct passwd_instance, ignore_empty), NULL, "yes" },
-
- { "allowmultiplekeys", PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED,
- offsetof(struct passwd_instance, allow_multiple), NULL, NULL },
- { "allow_multiple_keys", PW_TYPE_BOOLEAN,
- offsetof(struct passwd_instance, allow_multiple), NULL, "no" },
-
- { "hashsize", PW_TYPE_INTEGER | PW_TYPE_DEPRECATED,
- offsetof(struct passwd_instance, hash_size), NULL, NULL },
- { "hash_size", PW_TYPE_INTEGER,
- offsetof(struct passwd_instance, hash_size), NULL, "100" },
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_REQUIRED, struct passwd_instance, filename), NULL },
+ { "format", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, struct passwd_instance, format), NULL },
+ { "delimiter", FR_CONF_OFFSET(PW_TYPE_STRING, struct passwd_instance, delimiter), ":" },
+
+ { "ignorenislike", FR_CONF_OFFSET(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, struct passwd_instance, ignore_nislike), NULL },
+ { "ignore_nislike", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, struct passwd_instance, ignore_nislike), "yes" },
+
+ { "ignoreempty", FR_CONF_OFFSET(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, struct passwd_instance, ignore_empty), NULL },
+ { "ignore_empty", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, struct passwd_instance, ignore_empty), "yes" },
+
+ { "allowmultiplekeys", FR_CONF_OFFSET(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, struct passwd_instance, allow_multiple), NULL },
+ { "allow_multiple_keys", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, struct passwd_instance, allow_multiple), "no" },
+
+ { "hashsize", FR_CONF_OFFSET(PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, struct passwd_instance, hash_size), NULL },
+ { "hash_size", FR_CONF_OFFSET(PW_TYPE_INTEGER, struct passwd_instance, hash_size), "100" },
{ NULL, -1, 0, NULL, NULL }
};
static int mod_instantiate(CONF_SECTION *conf, void *instance)
{
int nfields=0, keyfield=-1, listable=0;
- char *s;
+ char const *s;
char *lf=NULL; /* destination list flags temporary */
size_t len;
int i;
return -1;
}
- lf = talloc_strdup(inst, inst->format);
+ lf = talloc_typed_strdup(inst, inst->format);
if ( !lf) {
ERROR("rlm_passwd: memory allocation failed for lf");
return -1;
if (! (inst->pwdfmt = mypasswd_malloc(inst->format, nfields, &len)) ){
ERROR("rlm_passwd: memory allocation failed");
release_ht(inst->ht);
+ inst->ht = NULL;
return -1;
}
if (!string_to_entry(inst->format, nfields, ':', inst->pwdfmt , len)) {
ERROR("rlm_passwd: unable to convert format entry");
release_ht(inst->ht);
+ inst->ht = NULL;
return -1;
}
if (!*inst->pwdfmt->field[keyfield]) {
cf_log_err_cs(conf, "key field is empty");
release_ht(inst->ht);
+ inst->ht = NULL;
return -1;
}
if (! (da = dict_attrbyname (inst->pwdfmt->field[keyfield])) ) {
ERROR("rlm_passwd: unable to resolve attribute: %s", inst->pwdfmt->field[keyfield]);
release_ht(inst->ht);
+ inst->ht = NULL;
return -1;
}
inst->keyattr = da;
static int mod_detach (void *instance) {
#define inst ((struct passwd_instance *)instance)
- if(inst->ht) release_ht(inst->ht);
+ if(inst->ht) {
+ release_ht(inst->ht);
+ inst->ht = NULL;
+ }
free(inst->pwdfmt);
return 0;
#undef inst
static void addresult (struct passwd_instance * inst, REQUEST *request, TALLOC_CTX *ctx, VALUE_PAIR **vps, struct mypasswd * pw, char when, char const *listname)
{
- int i;
+ uint32_t i;
VALUE_PAIR *vp;
- for (i=0; i<inst->nfields; i++) {
+ for (i = 0; i < inst->nfields; i++) {
if (inst->pwdfmt->field[i] && *inst->pwdfmt->field[i] && pw->field[i] && i != inst->keyfield && inst->pwdfmt->listflag[i] == when) {
if ( !inst->ignore_empty || pw->field[i][0] != 0 ) { /* if value in key/value pair is not empty */
vp = pairmake(ctx, vps, inst->pwdfmt->field[i], pw->field[i], T_OP_EQ);
}
}
-static rlm_rcode_t passwd_map(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_passwd_map(void *instance, REQUEST *request)
{
#define inst ((struct passwd_instance *)instance)
char buffer[1024];
return RLM_MODULE_NOTFOUND;
}
- for (i = paircursor(&cursor, &key);
+ for (i = fr_cursor_init(&cursor, &key);
i;
- i = pairfindnext(&cursor, inst->keyattr->attr, inst->keyattr->vendor, TAG_ANY)) {
+ i = fr_cursor_next_by_num(&cursor, inst->keyattr->attr, inst->keyattr->vendor, TAG_ANY)) {
/*
* Ensure we have the string form of the attribute
*/
module_t rlm_passwd = {
RLM_MODULE_INIT,
"passwd",
- RLM_TYPE_CHECK_CONFIG_SAFE | RLM_TYPE_HUP_SAFE, /* type */
+ RLM_TYPE_HUP_SAFE, /* type */
sizeof(struct passwd_instance),
module_config,
mod_instantiate, /* instantiation */
mod_detach, /* detach */
{
NULL, /* authentication */
- passwd_map, /* authorization */
+ mod_passwd_map, /* authorization */
NULL, /* pre-accounting */
- passwd_map, /* accounting */
+ mod_passwd_map, /* accounting */
NULL, /* checksimul */
NULL, /* pre-proxy */
NULL, /* post-proxy */
- passwd_map /* post-auth */
+ mod_passwd_map /* post-auth */
#ifdef WITH_COA
- , passwd_map,
- passwd_map
+ , mod_passwd_map,
+ mod_passwd_map
#endif
},
};
SRC_CFLAGS := @mod_cflags@
TGT_LDLIBS := @mod_ldflags@
-
-ifneq "$(TARGETNAME)" ""
-install: $(R)$(modconfdir)/perl/example.pl
-
-$(R)$(modconfdir)/perl: | $(R)$(modconfdir)
- @echo INSTALL $(patsubst $(R)$(raddbdir)%,raddb%,$@)
- @$(INSTALL) -d -m 750 $@
-
-$(R)$(modconfdir)/perl/example.pl: src/modules/rlm_perl/example.pl | $(R)$(modconfdir)/perl
- @$(ECHO) INSTALL $(notdir $<)
- @$(INSTALL) -m 755 $< $(R)$(modconfdir)/perl
-endif
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
CPP C preprocessor
PERL Absolute path to perl executable
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test -z "$PERL"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether perl executable path has been provided" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether perl executable path has been provided" >&5
$as_echo_n "checking whether perl executable path has been provided... " >&6; }
# Check whether --with-perl was given.
if test "${with_perl+set}" = set; then :
withval=$with_perl;
- if test "$withval" != yes && test "$withval" != no; then :
+ if test "$withval" != yes && test "$withval" != no; then :
- PERL="$withval"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5
+ PERL="$withval"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5
$as_echo "$PERL" >&6; }
else
- PERL=""
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+ PERL=""
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
- if test "$withval" != no; then :
+ if test "$withval" != no; then :
- # Extract the first word of "perl", so it can be a program name with args.
+ # Extract the first word of "perl", so it can be a program name with args.
set dummy perl; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
- # Extract the first word of "perl", so it can be a program name with args.
+ # Extract the first word of "perl", so it can be a program name with args.
set dummy perl; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=EXTERN.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=perl.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
--header=FILE[:TEMPLATE]
- instantiate the configuration header FILE
+ instantiate the configuration header FILE
Configuration files:
$config_files
*/
typedef struct rlm_perl_t {
/* Name of the perl module */
- char *module;
+ char const *module;
/* Name of the functions for each module method */
- char *func_authorize;
- char *func_authenticate;
- char *func_accounting;
- char *func_start_accounting;
- char *func_stop_accounting;
- char *func_preacct;
- char *func_checksimul;
- char *func_detach;
- char *func_xlat;
+ char const *func_authorize;
+ char const *func_authenticate;
+ char const *func_accounting;
+ char const *func_start_accounting;
+ char const *func_stop_accounting;
+ char const *func_preacct;
+ char const *func_checksimul;
+ char const *func_detach;
+ char const *func_xlat;
#ifdef WITH_PROXY
- char *func_pre_proxy;
- char *func_post_proxy;
+ char const *func_pre_proxy;
+ char const *func_post_proxy;
#endif
- char *func_post_auth;
+ char const *func_post_auth;
#ifdef WITH_COA
- char *func_recv_coa;
- char *func_send_coa;
+ char const *func_recv_coa;
+ char const *func_send_coa;
#endif
- char *xlat_name;
- char *perl_flags;
- PerlInterpreter *perl;
+ char const *xlat_name;
+ char const *perl_flags;
+ PerlInterpreter *perl;
pthread_key_t *thread_key;
#ifdef USE_ITHREADS
- pthread_mutex_t clone_mutex;
+ pthread_mutex_t clone_mutex;
#endif
+
+ HV *rad_perlconf_hv; //!< holds "config" items (perl %RAD_PERLCONF hash).
+
} rlm_perl_t;
/*
* A mapping of configuration file names to internal variables.
*/
-#define RLM_PERL_CONF(_x) { "func_" STRINGIFY(_x), PW_TYPE_STRING_PTR, \
+#define RLM_PERL_CONF(_x) { "func_" STRINGIFY(_x), PW_TYPE_STRING, \
offsetof(rlm_perl_t,func_##_x), NULL, STRINGIFY(_x)}
static const CONF_PARSER module_config[] = {
- { "module", PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED,
- offsetof(rlm_perl_t,module), NULL, NULL},
- { "filename", PW_TYPE_FILE_INPUT | PW_TYPE_REQUIRED,
- offsetof(rlm_perl_t,module), NULL, NULL},
+ { "module", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, rlm_perl_t, module), NULL },
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_REQUIRED, rlm_perl_t, module), NULL },
RLM_PERL_CONF(authorize),
RLM_PERL_CONF(authenticate),
RLM_PERL_CONF(recv_coa),
RLM_PERL_CONF(send_coa),
#endif
- { "perl_flags", PW_TYPE_STRING_PTR,
- offsetof(rlm_perl_t,perl_flags), NULL, NULL},
+ { "perl_flags", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_perl_t, perl_flags), NULL },
- { "func_start_accounting", PW_TYPE_STRING_PTR,
- offsetof(rlm_perl_t,func_start_accounting), NULL, NULL},
+ { "func_start_accounting", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_perl_t, func_start_accounting), NULL },
- { "func_stop_accounting", PW_TYPE_STRING_PTR,
- offsetof(rlm_perl_t,func_stop_accounting), NULL, NULL},
+ { "func_stop_accounting", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_perl_t, func_stop_accounting), NULL },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
PL_ptr_table = NULL;
PERL_SET_CONTEXT(aTHX);
- rlm_perl_clear_handles(aTHX);
+ rlm_perl_clear_handles(aTHX);
ret = pthread_setspecific(*key, interp);
if (ret != 0) {
- DEBUG("rlm_perl: Failed associating interpretor with thread %s", strerror(ret));
+ DEBUG("rlm_perl: Failed associating interpretor with thread %s", fr_syserror(ret));
rlm_perl_destruct(interp);
return NULL;
static ssize_t perl_xlat(void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
{
- rlm_perl_t *inst= (rlm_perl_t *) instance;
+ rlm_perl_t *inst = (rlm_perl_t *) instance;
char *tmp;
char const *p, *q;
int count;
return ret;
}
+
+/*
+ * Parse a configuration section, and populate a HV.
+ * This function is recursively called (allows to have nested hashes.)
+ */
+static void perl_parse_config(CONF_SECTION *cs, int lvl, HV *rad_hv)
+{
+ if (!cs || !rad_hv) return;
+
+ int indent_section = (lvl + 1) * 4;
+ int indent_item = (lvl + 2) * 4;
+
+ DEBUG("%*s%s {", indent_section, " ", cf_section_name1(cs));
+
+ CONF_ITEM *ci;
+
+ for (ci = cf_item_find_next(cs, NULL);
+ ci;
+ ci = cf_item_find_next(cs, ci)) {
+ /*
+ * This is a section.
+ * Create a new HV, store it as a reference in current HV,
+ * Then recursively call perl_parse_config with this section and the new HV.
+ */
+ if (cf_item_is_section(ci)) {
+ CONF_SECTION *sub_cs = cf_itemtosection(ci);
+ char const *key = cf_section_name1(sub_cs); /* hash key */
+ HV *sub_hv;
+ SV *ref;
+
+ if (!key) continue;
+
+ if (hv_exists(rad_hv, key, strlen(key))) {
+ WARN("rlm_perl: Ignoring duplicate config section '%s'", key);
+ continue;
+ }
+
+ sub_hv = newHV();
+ ref = newRV_inc((SV*) sub_hv);
+
+ (void)hv_store(rad_hv, key, strlen(key), ref, 0);
+
+ perl_parse_config(sub_cs, lvl + 1, sub_hv);
+ } else if (cf_item_is_pair(ci)){
+ CONF_PAIR *cp = cf_itemtopair(ci);
+ char const *key = cf_pair_attr(cp); /* hash key */
+ char const *value = cf_pair_value(cp); /* hash value */
+
+ if (!key || !value) continue;
+
+ /*
+ * This is an item.
+ * Store item attr / value in current HV.
+ */
+ if (hv_exists(rad_hv, key, strlen(key))) {
+ WARN("rlm_perl: Ignoring duplicate config item '%s'", key);
+ continue;
+ }
+
+ (void)hv_store(rad_hv, key, strlen(key), newSVpv(value, strlen(value)), 0);
+
+ DEBUG("%*s%s = %s", indent_item, " ", key, value);
+ }
+ }
+
+ DEBUG("%*s}", indent_section, " ");
+}
+
/*
* Do any per-module initialization that is separate to each
* configured instance of the module. e.g. set up connections
rlm_perl_t *inst = instance;
AV *end_AV;
+ char const **embed_c; /* Stupid Perl and lack of const consistency */
char **embed;
char **envp = NULL;
char const *xlat_name;
int exitstatus = 0, argc=0;
- MEM(embed = talloc_zero_array(inst, char *, 4));
-
+ MEM(embed_c = talloc_zero_array(inst, char const *, 4));
+ memcpy(&embed, &embed_c, sizeof(embed));
/*
* Create pthread key. This key will be stored in instance
*/
char arg[] = "0";
- embed[0] = NULL;
+ embed_c[0] = NULL;
if (inst->perl_flags) {
- embed[1] = inst->perl_flags;
- embed[2] = inst->module;
- embed[3] = arg;
+ embed_c[1] = inst->perl_flags;
+ embed_c[2] = inst->module;
+ embed_c[3] = arg;
argc = 4;
} else {
- embed[1] = inst->module;
- embed[2] = arg;
+ embed_c[1] = inst->module;
+ embed_c[2] = arg;
argc = 3;
}
PL_endav = Nullav;
if(!exitstatus) {
- exitstatus = perl_run(inst->perl);
+ perl_run(inst->perl);
} else {
ERROR("rlm_perl: perl_parse failed: %s not found or has syntax errors. \n", inst->module);
return (-1);
xlat_register(xlat_name, perl_xlat, NULL, inst);
}
+ /* parse perl configuration sub-section */
+ CONF_SECTION *cs;
+ cs = cf_section_sub_find(conf, "config");
+ if (cs) {
+ DEBUG("rlm_perl (%s): parsing 'config' section...", xlat_name);
+
+ inst->rad_perlconf_hv = get_hv("RAD_PERLCONF",1);
+ perl_parse_config(cs, 0, inst->rad_perlconf_hv);
+
+ DEBUG("rlm_perl (%s): done parsing 'config'.", xlat_name);
+ }
+
return 0;
}
* Example for this is Cisco-AVPair that holds multiple values.
* Which will be available as array_ref in $RAD_REQUEST{'Cisco-AVPair'}
*/
-static void perl_store_vps(TALLOC_CTX *ctx, VALUE_PAIR *vps, HV *rad_hv)
+static void perl_store_vps(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR *vps, HV *rad_hv)
{
VALUE_PAIR *head, *sublist;
AV *av;
char const *name;
char namebuf[256];
char buffer[1024];
- int len;
+ size_t len;
hv_undef(rad_hv);
while (head) {
vp_cursor_t cursor;
+
/*
* Tagged attributes are added to the hash with name
* <attribute>:<tag>, others just use the normal attribute
sublist = NULL;
pairfilter(ctx, &sublist, &head, head->da->attr, head->da->vendor, head->tag);
- paircursor(&cursor, &sublist);
+ fr_cursor_init(&cursor, &sublist);
+
/*
* Attribute has multiple values
*/
- if (pairnext(&cursor)) {
+ if (fr_cursor_next(&cursor)) {
VALUE_PAIR *vp;
av = newAV();
- for (vp = pairfirst(&cursor);
+ for (vp = fr_cursor_first(&cursor);
vp;
- vp = pairnext(&cursor)) {
- len = vp_prints_value(buffer, sizeof(buffer), vp, 0);
- av_push(av, newSVpv(buffer, len));
+ vp = fr_cursor_next(&cursor)) {
+ if (vp->da->type != PW_TYPE_STRING) {
+ len = vp_prints_value(buffer, sizeof(buffer), vp, 0);
+ av_push(av, newSVpv(buffer, truncate_len(len, sizeof(buffer))));
+ RDEBUG("<-- %s = %s", vp->da->name, buffer);
+ } else {
+ av_push(av, newSVpv(vp->vp_strvalue, vp->length));
+ RDEBUG("<-- %s = %s", vp->da->name, vp->vp_strvalue);
+ }
}
(void)hv_store(rad_hv, name, strlen(name), newRV_noinc((SV *)av), 0);
* Attribute has a single value, so its value just gets
* added to the hash.
*/
- } else {
- len = vp_prints_value(buffer, sizeof(buffer), sublist, 0);
- (void)hv_store(rad_hv, name, strlen(name), newSVpv(buffer, len), 0);
+ } else if (sublist) {
+
+ if (sublist->da->type != PW_TYPE_STRING) {
+ len = vp_prints_value(buffer, sizeof(buffer), sublist, 0);
+ (void)hv_store(rad_hv, name, strlen(name), newSVpv(buffer, truncate_len(len, sizeof(buffer))), 0);
+ RDEBUG("<-- %s = %s", sublist->da->name, buffer);
+ } else {
+ (void)hv_store(rad_hv, name, strlen(name), newSVpv(sublist->vp_strvalue, sublist->length), 0);
+ RDEBUG("<-- %s = %s", sublist->da->name, sublist->vp_strvalue);
+ }
}
pairfree(&sublist);
* Value Pair Format
*
*/
-static int pairadd_sv(TALLOC_CTX *ctx, VALUE_PAIR **vps, char *key, SV *sv, FR_TOKEN op)
+static int pairadd_sv(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **vps, char *key, SV *sv, FR_TOKEN op)
{
char *val;
VALUE_PAIR *vp;
if (SvOK(sv)) {
- val = SvPV_nolen(sv);
- vp = pairmake(ctx, vps, key, val, op);
- if (vp != NULL) {
- DEBUG("rlm_perl: Added pair %s = %s", key, val);
- return 1;
+ STRLEN len;
+ val = SvPV(sv, len);
+ vp = pairmake(ctx, vps, key, NULL, op);
+ if (!vp) {
+ fail:
+ REDEBUG("Failed to create pair %s = %s", key, val);
+ return 0;
+ }
+
+ if (vp->da->type != PW_TYPE_STRING) {
+ if (pairparsevalue(vp, val, 0) < 0) goto fail;
} else {
- EDEBUG("rlm_perl: Failed to create pair %s = %s", key, val);
+ pairstrncpy(vp, val, len);
}
+
+ RDEBUG("--> %s = %s", key, val);
+ return 1;
}
return 0;
}
* Boyan :
* Gets the content from hashes
*/
-static int get_hv_content(TALLOC_CTX *ctx, HV *my_hv, VALUE_PAIR **vps)
+static int get_hv_content(TALLOC_CTX *ctx, REQUEST *request, HV *my_hv, VALUE_PAIR **vps)
{
SV *res_sv, **av_sv;
AV *av;
len = av_len(av);
for (j = 0; j <= len; j++) {
av_sv = av_fetch(av, j, 0);
- ret = pairadd_sv(ctx, vps, key, *av_sv, T_OP_ADD) + ret;
+ ret = pairadd_sv(ctx, request, vps, key, *av_sv, T_OP_ADD) + ret;
}
- } else ret = pairadd_sv(ctx, vps, key, res_sv, T_OP_EQ) + ret;
+ } else ret = pairadd_sv(ctx, request, vps, key, res_sv, T_OP_EQ) + ret;
}
return ret;
* Store all vps in hashes %RAD_CHECK %RAD_REPLY %RAD_REQUEST
*
*/
-static int do_perl(void *instance, REQUEST *request, char *function_name)
+static int do_perl(void *instance, REQUEST *request, char const *function_name)
{
rlm_perl_t *inst = instance;
rad_config_hv = get_hv("RAD_CONFIG",1);
rad_request_hv = get_hv("RAD_REQUEST",1);
- perl_store_vps(request->reply, request->reply->vps, rad_reply_hv);
- perl_store_vps(request, request->config_items, rad_check_hv);
- perl_store_vps(request->packet, request->packet->vps, rad_request_hv);
- perl_store_vps(request, request->config_items, rad_config_hv);
+ perl_store_vps(request->reply, request, request->reply->vps, rad_reply_hv);
+ perl_store_vps(request, request, request->config_items, rad_check_hv);
+ perl_store_vps(request->packet, request, request->packet->vps, rad_request_hv);
+ perl_store_vps(request, request, request->config_items, rad_config_hv);
#ifdef WITH_PROXY
rad_request_proxy_hv = get_hv("RAD_REQUEST_PROXY",1);
rad_request_proxy_reply_hv = get_hv("RAD_REQUEST_PROXY_REPLY",1);
if (request->proxy != NULL) {
- perl_store_vps(request->proxy, request->proxy->vps, rad_request_proxy_hv);
+ perl_store_vps(request->proxy, request, request->proxy->vps, rad_request_proxy_hv);
} else {
hv_undef(rad_request_proxy_hv);
}
if (request->proxy_reply !=NULL) {
- perl_store_vps(request->proxy_reply, request->proxy_reply->vps, rad_request_proxy_reply_hv);
+ perl_store_vps(request->proxy_reply, request, request->proxy_reply->vps, rad_request_proxy_reply_hv);
} else {
hv_undef(rad_request_proxy_reply_hv);
}
LEAVE;
vp = NULL;
- if ((get_hv_content(request->packet, rad_request_hv, &vp)) > 0 ) {
+ if ((get_hv_content(request->packet, request, rad_request_hv, &vp)) > 0 ) {
pairfree(&request->packet->vps);
request->packet->vps = vp;
vp = NULL;
request->password = pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY);
}
- if ((get_hv_content(request->reply, rad_reply_hv, &vp)) > 0 ) {
+ if ((get_hv_content(request->reply, request, rad_reply_hv, &vp)) > 0 ) {
pairfree(&request->reply->vps);
request->reply->vps = vp;
vp = NULL;
}
- if ((get_hv_content(request, rad_check_hv, &vp)) > 0 ) {
+ if ((get_hv_content(request, request, rad_check_hv, &vp)) > 0 ) {
pairfree(&request->config_items);
request->config_items = vp;
vp = NULL;
#ifdef WITH_PROXY
if (request->proxy &&
- (get_hv_content(request->proxy, rad_request_proxy_hv, &vp) > 0)) {
+ (get_hv_content(request->proxy, request, rad_request_proxy_hv, &vp) > 0)) {
pairfree(&request->proxy->vps);
request->proxy->vps = vp;
vp = NULL;
}
if (request->proxy_reply &&
- (get_hv_content(request->proxy_reply, rad_request_proxy_reply_hv, &vp) > 0)) {
+ (get_hv_content(request->proxy_reply, request, rad_request_proxy_reply_hv, &vp) > 0)) {
pairfree(&request->proxy_reply->vps);
request->proxy_reply->vps = vp;
vp = NULL;
return exitstatus;
}
-#define RLM_PERL_FUNC(_x) static rlm_rcode_t mod_##_x(void *instance, REQUEST *request) \
+#define RLM_PERL_FUNC(_x) static rlm_rcode_t CC_HINT(nonnull) mod_##_x(void *instance, REQUEST *request) \
{ \
return do_perl(instance, request, \
((rlm_perl_t *)instance)->func_##_x); \
/*
* Write accounting information to this modules database.
*/
-static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
{
VALUE_PAIR *pair;
int acctstatustype=0;
rlm_perl_t *inst = (rlm_perl_t *) instance;
int exitstatus = 0, count = 0;
+ hv_undef(inst->rad_perlconf_hv);
+
#if 0
/*
* FIXME: Call this in the destruct function?
#include <ctype.h>
typedef struct rlm_preprocess_t {
- char *huntgroup_file;
- char *hints_file;
+ char const *huntgroup_file;
+ char const *hints_file;
PAIR_LIST *huntgroups;
PAIR_LIST *hints;
bool with_ascend_hack;
- int ascend_channels_per_line;
+ uint32_t ascend_channels_per_line;
bool with_ntdomain_hack;
bool with_specialix_jetstream_hack;
bool with_cisco_vsa_hack;
} rlm_preprocess_t;
static const CONF_PARSER module_config[] = {
- { "huntgroups", PW_TYPE_FILE_INPUT,
- offsetof(rlm_preprocess_t,huntgroup_file), NULL, NULL },
- { "hints", PW_TYPE_FILE_INPUT,
- offsetof(rlm_preprocess_t,hints_file), NULL, NULL },
- { "with_ascend_hack", PW_TYPE_BOOLEAN,
- offsetof(rlm_preprocess_t,with_ascend_hack), NULL, "no" },
- { "ascend_channels_per_line", PW_TYPE_INTEGER,
- offsetof(rlm_preprocess_t,ascend_channels_per_line), NULL, "23" },
-
- { "with_ntdomain_hack", PW_TYPE_BOOLEAN,
- offsetof(rlm_preprocess_t,with_ntdomain_hack), NULL, "no" },
- { "with_specialix_jetstream_hack", PW_TYPE_BOOLEAN,
- offsetof(rlm_preprocess_t,with_specialix_jetstream_hack), NULL,
- "no" },
- { "with_cisco_vsa_hack", PW_TYPE_BOOLEAN,
- offsetof(rlm_preprocess_t,with_cisco_vsa_hack), NULL, "no" },
- { "with_alvarion_vsa_hack", PW_TYPE_BOOLEAN,
- offsetof(rlm_preprocess_t,with_alvarion_vsa_hack), NULL, "no" },
+ { "huntgroups", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_preprocess_t, huntgroup_file), NULL },
+ { "hints", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_preprocess_t, hints_file), NULL },
+ { "with_ascend_hack", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_preprocess_t, with_ascend_hack), "no" },
+ { "ascend_channels_per_line", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_preprocess_t, ascend_channels_per_line), "23" },
+
+ { "with_ntdomain_hack", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_preprocess_t, with_ntdomain_hack), "no" },
+ { "with_specialix_jetstream_hack", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_preprocess_t, with_specialix_jetstream_hack), "no" },
+ { "with_cisco_vsa_hack", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_preprocess_t, with_cisco_vsa_hack), "no" },
+ { "with_alvarion_vsa_hack", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_preprocess_t, with_alvarion_vsa_hack), "no" },
#if 0
- { "with_cablelabs_vsa_hack", PW_TYPE_BOOLEAN,
- offsetof(rlm_preprocess_t,with_cablelabs_vsa_hack), NULL, NULL },
+ { "with_cablelabs_vsa_hack", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_preprocess_t, with_cablelabs_vsa_hack), NULL },
#endif
{ NULL, -1, 0, NULL, NULL }
};
char newattr[MAX_STRING_LEN];
VALUE_PAIR *vp;
vp_cursor_t cursor;
- for (vp = paircursor(&cursor, &request->packet->vps);
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
vendorcode = vp->da->vendor;
if (!((vendorcode == 9) || (vendorcode == 6618))) {
continue; /* not a Cisco or Quintum VSA, continue */
char const *p;
p = vp->vp_strvalue;
- gettoken(&p, newattr, sizeof(newattr));
+ gettoken(&p, newattr, sizeof(newattr), false);
if (dict_attrbyname(newattr) != NULL) {
pairmake_packet(newattr, ptr + 1, T_OP_EQ);
int number = 1;
vp_cursor_t cursor;
- for (vp = paircursor(&cursor, &vp);
+ for (vp = fr_cursor_init(&cursor, &vp);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
DICT_ATTR const *da;
if (vp->da->vendor != 12394) {
*/
request_pairs = request->packet->vps;
namepair = pairfind(request_pairs, PW_USER_NAME, 0, TAG_ANY);
- if ((!namepair) || (namepair->length <= 0)) {
+ if (!namepair || (namepair->length == 0)) {
return;
}
*/
if (pairfind(request_pairs, PW_FRAMED_PROTOCOL, 0, TAG_ANY) != NULL &&
pairfind(request_pairs, PW_SERVICE_TYPE, 0, TAG_ANY) == NULL) {
- tmp = radius_paircreate(request, &request->packet->vps, PW_SERVICE_TYPE, 0);
+ tmp = radius_paircreate(request->packet, &request->packet->vps, PW_SERVICE_TYPE, 0);
tmp->vp_integer = PW_FRAMED_USER;
}
num_proxy_state = 0;
- for (tmp = paircursor(&cursor, &request->packet->vps);
+ for (tmp = fr_cursor_init(&cursor, &request->packet->vps);
tmp;
- tmp = pairnext(&cursor)) {
+ tmp = fr_cursor_next(&cursor)) {
if (tmp->da->vendor != 0) {
continue;
}
}
if (num_proxy_state > 10) {
- RWDEBUG("There are more than 10 Proxy-State attributes in the request.");
- RWDEBUG("You have likely configured an infinite proxy loop.");
+ RWDEBUG("There are more than 10 Proxy-State attributes in the request");
+ RWDEBUG("You have likely configured an infinite proxy loop");
}
}
if (!check) return 0;
- for (check_item = paircursor(&cursor, &check);
+ for (check_item = fr_cursor_init(&cursor, &check);
check_item && (result != 0);
- check_item = pairnext(&cursor)) {
- /* FIXME: paircopy should be removed once VALUE_PAIRs are no longer in linked lists */
+ check_item = fr_cursor_next(&cursor)) {
+ /* FIXME: paircopy should be removed once VALUE_PAIRs are no longer in linked lists */
tmp = paircopyvp(request, check_item);
tmp->op = check_item->op;
result = paircompare(req, request, check_item, NULL);
*/
if (((strcmp(i->name, "DEFAULT") == 0) || (strcmp(i->name, name) == 0)) &&
(paircompare(request, request_pairs, i->check, NULL) == 0)) {
- RDEBUG2(" hints: Matched %s at %d", i->name, i->lineno);
+ RDEBUG2("hints: Matched %s at %d", i->name, i->lineno);
/*
* Now add all attributes to the request list,
* except PW_STRIP_USER_NAME and PW_FALL_THROUGH
pairdelete(&add, PW_STRIP_USER_NAME, 0, TAG_ANY);
pairdelete(&add, PW_FALL_THROUGH, 0, TAG_ANY);
- radius_xlat_move(request, &request->packet->vps, &add);
+ radius_pairmove(request, &request->packet->vps, add, true);
- pairfree(&add);
updated = 1;
if (!ft) {
break;
*/
vp = pairfind(request_pairs, PW_HUNTGROUP_NAME, 0, TAG_ANY);
if (!vp) {
- vp = radius_paircreate(request, &request->packet->vps, PW_HUNTGROUP_NAME, 0);
+ vp = radius_paircreate(request->packet, &request->packet->vps, PW_HUNTGROUP_NAME, 0);
pairstrcpy(vp, i->name);
}
r = RLM_MODULE_OK;
case AF_INET:
nas = pairfind(request->packet->vps, PW_NAS_IP_ADDRESS, 0, TAG_ANY);
if (!nas) {
- nas = radius_paircreate(request, &request->packet->vps, PW_NAS_IP_ADDRESS, 0);
+ nas = radius_paircreate(request->packet, &request->packet->vps, PW_NAS_IP_ADDRESS, 0);
nas->vp_ipaddr = request->packet->src_ipaddr.ipaddr.ip4addr.s_addr;
}
break;
case AF_INET6:
nas = pairfind(request->packet->vps, PW_NAS_IPV6_ADDRESS, 0, TAG_ANY);
if (!nas) {
- nas = radius_paircreate(request, &request->packet->vps, PW_NAS_IPV6_ADDRESS, 0);
+ nas = radius_paircreate(request->packet, &request->packet->vps, PW_NAS_IPV6_ADDRESS, 0);
memcpy(&nas->vp_ipv6addr, &request->packet->src_ipaddr.ipaddr,
sizeof(request->packet->src_ipaddr.ipaddr));
}
/*
* Preprocess a request.
*/
-static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
{
int r;
rlm_preprocess_t *inst = instance;
}
if (inst->with_cisco_vsa_hack) {
- /*
+ /*
* We need to run this hack because the h323-conf-id
* attribute should be used.
*/
}
if (inst->with_alvarion_vsa_hack) {
- /*
+ /*
* We need to run this hack because the Alvarion
* people are crazy.
*/
}
if (inst->with_cablelabs_vsa_hack) {
- /*
+ /*
* We need to run this hack because the Cablelabs
* people are crazy.
*/
if (pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY) &&
pairfind(request->packet->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY) == NULL) {
VALUE_PAIR *vp;
- uint8_t *p;
- vp = radius_paircreate(request, &request->packet->vps, PW_CHAP_CHALLENGE, 0);
- vp->length = AUTH_VECTOR_LEN;
- vp->vp_octets = p = talloc_array(vp, uint8_t, vp->length);
-
- memcpy(p, request->packet->vector, AUTH_VECTOR_LEN);
+ vp = radius_paircreate(request->packet, &request->packet->vps, PW_CHAP_CHALLENGE, 0);
+ pairmemcpy(vp, request->packet->vector, AUTH_VECTOR_LEN);
}
if ((r = huntgroup_access(request, inst->huntgroups)) != RLM_MODULE_OK) {
/*
* Preprocess a request before accounting
*/
-static rlm_rcode_t preprocess_preaccounting(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_preaccounting(void *instance, REQUEST *request)
{
int r;
VALUE_PAIR *vp;
rad_mangle(inst, request);
if (inst->with_cisco_vsa_hack) {
- /*
+ /*
* We need to run this hack because the h323-conf-id
* attribute should be used.
*/
}
if (inst->with_alvarion_vsa_hack) {
- /*
+ /*
* We need to run this hack because the Alvarion
* people are crazy.
*/
}
if (inst->with_cablelabs_vsa_hack) {
- /*
+ /*
* We need to run this hack because the Cablelabs
* people are crazy.
*/
if (!vp) {
VALUE_PAIR *delay;
- vp = radius_paircreate(request, &request->packet->vps, PW_EVENT_TIMESTAMP, 0);
+ vp = radius_paircreate(request->packet, &request->packet->vps, PW_EVENT_TIMESTAMP, 0);
vp->vp_date = request->packet->timestamp.tv_sec;
delay = pairfind(request->packet->vps, PW_ACCT_DELAY_TIME, 0, TAG_ANY);
if ((r = huntgroup_access(request, inst->huntgroups)) != RLM_MODULE_OK) {
char buf[1024];
RIDEBUG("No huntgroup access: [%s] (%s)",
- request->username ? request->username->vp_strvalue : "<NO User-Name>",
- auth_name(buf, sizeof(buf), request, 1));
+ request->username ? request->username->vp_strvalue : "<NO User-Name>",
+ auth_name(buf, sizeof(buf), request, 1));
return r;
}
module_t rlm_preprocess = {
RLM_MODULE_INIT,
"preprocess",
- RLM_TYPE_CHECK_CONFIG_SAFE, /* type */
+ 0, /* type */
sizeof(rlm_preprocess_t),
module_config,
mod_instantiate, /* instantiation */
{
NULL, /* authentication */
mod_authorize, /* authorization */
- preprocess_preaccounting, /* pre-accounting */
+ mod_preaccounting, /* pre-accounting */
NULL, /* accounting */
NULL, /* checksimul */
NULL, /* pre-proxy */
TGT_LDLIBS := @mod_ldflags@
ifneq "$(TARGETNAME)" ""
-install: $(R)$(modconfdir)/python/example.py
+install: $(R)$(modconfdir)/python/radiusd.py $(R)$(modconfdir)/python/example.py
$(R)$(modconfdir)/python: | $(R)$(modconfdir)
@echo INSTALL $(patsubst $(R)$(raddbdir)%,raddb%,$@)
@$(INSTALL) -d -m 750 $@
+$(R)$(modconfdir)/python/radiusd.py: src/modules/rlm_python/radiusd.py | $(R)$(modconfdir)/python
+ @$(ECHO) INSTALL $(notdir $<)
+ @$(INSTALL) -m 755 $< $(R)$(modconfdir)/python
+
$(R)$(modconfdir)/python/example.py: src/modules/rlm_python/example.py | $(R)$(modconfdir)/python
@$(ECHO) INSTALL $(notdir $<)
@$(INSTALL) -m 755 $< $(R)$(modconfdir)/python
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
CPP C preprocessor
Use these variables to override the choices made by `configure' or to help
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
ac_safe=`echo "Python.h" | sed 'y%./+-%__pm%'`
-old_CFLAGS="$CFLAGS"
+old_CPPFLAGS="$CPPFLAGS"
smart_include=
smart_include_dir=
for try in $smart_try_dir; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Python.h in $try" >&5
$as_echo_n "checking for Python.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_include" = "x"; then
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=Python.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
for try in $smart_include_dir /usr/local/include /opt/include; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Python.h in $try" >&5
$as_echo_n "checking for Python.h in $try... " >&6; }
- CFLAGS="$old_CFLAGS -isystem $try"
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
done
- CFLAGS="$old_CFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_include" != "x"; then
eval "ac_cv_header_$ac_safe=yes"
- CFLAGS="$old_CFLAGS $smart_include"
- SMART_CFLAGS="$SMART_CFLAGS $smart_include"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
fi
CFLAGS=$old_CFLAGS
if test "x$ac_cv_header_Python_h" = "xyes"; then
- mod_cflags=${SMART_CFLAGS}
+ mod_cflags="$SMART_CPPFLAGS"
else
fail="$fail Python.h"
targetname=
sm_func_safe=`echo "Py_Initialize" | 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 Py_Initialize in -lpython${PY_VERSION} in $try" >&5
$as_echo_n "checking for Py_Initialize in -lpython${PY_VERSION} in $try... " >&6; }
- LIBS="-L$try -lpython${PY_VERSION} $old_LIBS -Wl,-rpath,$try"
+ LIBS="-lpython${PY_VERSION} $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
extern char Py_Initialize();
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-L$try -lpython${PY_VERSION} -Wl,-rpath,$try"
+ smart_lib="-lpython${PY_VERSION}"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
break
conftest$ac_exeext conftest.$ac_ext
done
LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_lib" = "x"; then
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lpython${PY_VERSION}"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lpython${PY_VERSION}"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libpython${PY_VERSION}${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libpython${PY_VERSION}.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
for try in $smart_lib_dir /usr/local/lib /opt/lib; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Py_Initialize in -lpython${PY_VERSION} in $try" >&5
$as_echo_n "checking for Py_Initialize in -lpython${PY_VERSION} in $try... " >&6; }
- LIBS="-L$try -lpython${PY_VERSION} $old_LIBS -Wl,-rpath,$try"
+ LIBS="-lpython${PY_VERSION} $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
extern char Py_Initialize();
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-L$try -lpython${PY_VERSION} -Wl,-rpath,$try"
+ smart_lib="-lpython${PY_VERSION}"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
break
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_lib $old_LIBS"
- SMART_LIBS="$smart_lib $SMART_LIBS"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
fi
LIBS=$old_LIBS
sm_func_safe=`echo "Py_Initialize" | 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 Py_Initialize in -lpython${PY_VERSION}m in $try" >&5
$as_echo_n "checking for Py_Initialize in -lpython${PY_VERSION}m in $try... " >&6; }
- LIBS="-L$try -lpython${PY_VERSION}m $old_LIBS -Wl,-rpath,$try"
+ LIBS="-lpython${PY_VERSION}m $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
extern char Py_Initialize();
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-L$try -lpython${PY_VERSION}m -Wl,-rpath,$try"
+ smart_lib="-lpython${PY_VERSION}m"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
break
conftest$ac_exeext conftest.$ac_ext
done
LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
fi
if test "x$smart_lib" = "x"; then
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lpython${PY_VERSION}m"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lpython${PY_VERSION}m"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libpython${PY_VERSION}m${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libpython${PY_VERSION}m.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
for try in $smart_lib_dir /usr/local/lib /opt/lib; do
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Py_Initialize in -lpython${PY_VERSION}m in $try" >&5
$as_echo_n "checking for Py_Initialize in -lpython${PY_VERSION}m in $try... " >&6; }
- LIBS="-L$try -lpython${PY_VERSION}m $old_LIBS -Wl,-rpath,$try"
+ LIBS="-lpython${PY_VERSION}m $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
extern char Py_Initialize();
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-L$try -lpython${PY_VERSION}m -Wl,-rpath,$try"
+ smart_lib="-lpython${PY_VERSION}m"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
break
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_lib $old_LIBS"
- SMART_LIBS="$smart_lib $SMART_LIBS"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
fi
eval t=\${ac_cv_lib_${sm_lib_safe}_${sm_func_safe}}
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
CFLAGS=$old_CFLAGS
if test "x$ac_cv_header_Python_h" = "xyes"; then
- mod_cflags=${SMART_CFLAGS}
+ mod_cflags="$SMART_CPPFLAGS"
else
fail="$fail Python.h"
targetname=
if test "x$t" = "xyes"; then
mod_ldflags="$PY_LIB_LOC $PY_EXTRA_LIBS $SMART_LIBS -lm"
targetname=modname
- else
+ else
targetname=
fail="$fail libpython$PY_VERSION"
- fi
+ fi
fi
fi
else
#! /usr/bin/env python
#
-# Definitions for RADIUS programs
-#
-# Copyright 2002 Miguel A.L. Paraz <mparaz@mparaz.com>
-#
-# This should only be used when testing modules.
-# Inside freeradius, the 'radiusd' Python module is created by the C module
-# and the definitions are automatically created.
+# Python module example file
+# Miguel A.L. Paraz <mparaz@mparaz.com>
#
# $Id$
-# from modules.h
-
-RLM_MODULE_REJECT = 0
-RLM_MODULE_FAIL = 1
-RLM_MODULE_OK = 2
-RLM_MODULE_HANDLED = 3
-RLM_MODULE_INVALID = 4
-RLM_MODULE_USERLOCK = 5
-RLM_MODULE_NOTFOUND = 6
-RLM_MODULE_NOOP = 7
-RLM_MODULE_UPDATED = 8
-RLM_MODULE_NUMCODES = 9
-
-
-# from radiusd.h
-L_DBG = 1
-L_AUTH = 2
-L_INFO = 3
-L_ERR = 4
-L_PROXY = 5
-L_CONS = 128
-
-OP={ '{':2, '}':3, '(':4, ')':5, ',':6, ';':7, '+=':8, '-=':9, ':=':10,
- '=':11, '!=':12, '>=':13, '>':14, '<=':15, '<':16, '=~':17, '!~':18, '=*':19, '!*':20,
- '==':21 , '#':22 }
-
-OP_TRY = (':=', '+=', '-=', '=' )
-
-def resolve(*lines):
- tuples = []
- for line in lines:
- for op in OP_TRY:
- arr = line.rsplit(op)
- if len(arr)==2:
- tuples.append((str(arr[0].strip()),OP[op],str(arr[1].strip())))
- break
- return tuple(tuples)
-
-# log function
-def radlog(level, msg):
- import sys
- sys.stdout.write(msg + '\n')
-
- level = level
-
+import radiusd
+
+def instantiate(p):
+ print "*** instantiate ***"
+ print p
+
+def authorize(p):
+ print "*** authorize ***"
+ print
+ radiusd.radlog(radiusd.L_INFO, '*** radlog call in authorize ***')
+ print
+ print p
+ return radiusd.RLM_MODULE_OK
+
+def preacct(p):
+ print "*** preacct ***"
+ print p
+ return radiusd.RLM_MODULE_OK
+
+def accounting(p):
+ print "*** accounting ***"
+ radiusd.radlog(radiusd.L_INFO, '*** radlog call in accounting (0) ***')
+ print
+ print p
+ return radiusd.RLM_MODULE_OK
+
+def pre_proxy(p):
+ print "*** pre_proxy ***"
+ print p
+ return radiusd.RLM_MODULE_OK
+
+def post_proxy(p):
+ print "*** post_proxy ***"
+ print p
+ return radiusd.RLM_MODULE_OK
+
+def post_auth(p):
+ print "*** post_auth ***"
+ print p
+ return radiusd.RLM_MODULE_OK
+
+def recv_coa(p):
+ print "*** recv_coa ***"
+ print p
+ return radiusd.RLM_MODULE_OK
+
+def send_coa(p):
+ print "*** send_coa ***"
+ print p
+ return radiusd.RLM_MODULE_OK
+
+
+def detach():
+ print "*** goodbye from example.py ***"
+ return radiusd.RLM_MODULE_OK
try:
dbHandle = MySQLdb.connect(db=configDb, host=configHost,
- user=configUser, passwd=configPasswd)
+ user=configUser, passwd=configPasswd)
except MySQLdb.OperationalError, e:
# Report the error and return -1 for failure.
# We need to set an Auth-Type.
return (radiusd.RLM_MODULE_UPDATED,
- (('Session-Timeout', str(sessionTimeout)),),
- (('Auth-Type', 'python'),))
+ (('Session-Timeout', str(sessionTimeout)),),
+ (('Auth-Type', 'python'),))
# If you want to use different operators
# you can do
# return (radiusd.RLM_MODULE_UPDATED,
# xxx This is simplistic as it does not record the time, etc.
#
sql = 'insert into sessions (username, seconds) values (%s, %d)' % \
- (userName, int(acctSessionTime))
+ (userName, int(acctSessionTime))
log(radiusd.L_DBG, sql)
def resolve(*lines):
tuples = []
for line in lines:
- for op in OP_TRY:
- arr = line.rsplit(op)
- if len(arr)==2:
- tuples.append((str(arr[0].strip()),OP[op],str(arr[1].strip())))
- break
+ for op in OP_TRY:
+ arr = line.rsplit(op)
+ if len(arr)==2:
+ tuples.append((str(arr[0].strip()),OP[op],str(arr[1].strip())))
+ break
return tuple(tuples)
# log function
#include <Python.h>
#include <dlfcn.h>
+#ifdef HAVE_PTHREAD_H
#define Pyx_BLOCK_THREADS {PyGILState_STATE __gstate = PyGILState_Ensure();
#define Pyx_UNBLOCK_THREADS PyGILState_Release(__gstate);}
+#else
+#define Pyx_BLOCK_THREADS
+#define Pyx_UNBLOCK_THREADS
+#endif
/*
* TODO: The only needed thing here is function. Anything else is
* symbolic constant here instead.
*/
struct py_function_def {
- PyObject *module;
- PyObject *function;
+ PyObject *module;
+ PyObject *function;
- char *module_name;
- char *function_name;
+ char const *module_name;
+ char const *function_name;
};
typedef struct rlm_python_t {
+ void *libpython;
+ PyThreadState *main_thread_state;
+ char const *python_path;
+
struct py_function_def
instantiate,
- authorize,
- authenticate,
- preacct,
- accounting,
- checksimul,
- pre_proxy,
- post_proxy,
- post_auth,
+ authorize,
+ authenticate,
+ preacct,
+ accounting,
+ checksimul,
+ pre_proxy,
+ post_proxy,
+ post_auth,
#ifdef WITH_COA
- recv_coa,
- send_coa,
+ recv_coa,
+ send_coa,
#endif
- detach;
+ detach;
} rlm_python_t;
/*
* A mapping of configuration file names to internal variables.
- *
- * Note that the string is dynamically allocated, so it MUST
- * be freed. When the configuration file parse re-reads the string,
- * it free's the old one, and strdup's the new one, placing the pointer
- * to the strdup'd string into 'config.string'. This gets around
- * buffer over-flows.
*/
static CONF_PARSER module_config[] = {
-#define A(x) { "mod_" #x, PW_TYPE_STRING_PTR, offsetof(rlm_python_t, x.module_name), NULL, NULL }, \
- { "func_" #x, PW_TYPE_STRING_PTR, offsetof(rlm_python_t, x.function_name), NULL, NULL },
+#define A(x) { "mod_" #x, FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, x.module_name), NULL }, \
+ { "func_" #x, FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, x.function_name), NULL },
A(instantiate)
A(authorize)
#undef A
+ { "python_path", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, python_path), NULL },
+
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
{ NULL, 0 },
};
+/*
+ * This allows us to initialise PyThreadState on a per thread basis
+ */
+fr_thread_local_setup(PyThreadState *, local_thread_state); /* macro */
+
/*
* Let assume that radiusd module is only one since we have only
static void mod_error(void)
{
- PyObject
- *pType = NULL,
- *pValue = NULL,
- *pTraceback = NULL,
- *pStr1 = NULL,
- *pStr2 = NULL;
+ PyObject *pType = NULL, *pValue = NULL, *pTraceback = NULL, *pStr1 = NULL, *pStr2 = NULL;
- Pyx_BLOCK_THREADS
+ /* This will be called with the GIL lock held */
- PyErr_Fetch(&pType, &pValue, &pTraceback);
+ PyErr_Fetch(&pType, &pValue, &pTraceback);
if (!pType || !pValue)
goto failed;
if (((pStr1 = PyObject_Str(pType)) == NULL) ||
Py_XDECREF(pType);
Py_XDECREF(pValue);
Py_XDECREF(pTraceback);
+}
- Pyx_UNBLOCK_THREADS
- }
-
-static int mod_init(void)
+static int mod_init(rlm_python_t *inst)
{
int i;
static char name[] = "radiusd";
/*
* Explicitly load libpython, so symbols will be available to lib-dynload modules
*/
- if (!dlopen("libpython" STRINGIFY(PY_MAJOR_VERSION) "." STRINGIFY(PY_MINOR_VERSION) ".so",
- RTLD_NOW | RTLD_GLOBAL)) {
- WARN("Failed loading libpython symbols into global symbol table: %s", dlerror());
+ inst->libpython = dlopen("libpython" STRINGIFY(PY_MAJOR_VERSION) "." STRINGIFY(PY_MINOR_VERSION) ".so",
+ RTLD_NOW | RTLD_GLOBAL);
+ if (!inst->libpython) {
+ WARN("Failed loading libpython symbols into global symbol table: %s", dlerror());
}
Py_SetProgramName(name);
+#ifdef HAVE_PTHREAD_H
Py_InitializeEx(0); /* Don't override signal handlers */
PyEval_InitThreads(); /* This also grabs a lock */
+ inst->main_thread_state = PyThreadState_Get(); /* We need this for setting up thread local stuff */
+#endif
+ if (inst->python_path) {
+ char *path;
+
+ memcpy(&path, &inst->python_path, sizeof(path));
+ PySys_SetPath(path);
+ }
+
if ((radiusd_module = Py_InitModule3("radiusd", radiusd_methods,
- "FreeRADIUS Module.")) == NULL)
+ "FreeRADIUS Module")) == NULL)
goto failed;
for (i = 0; radiusd_constants[i].name; i++) {
}
}
- PyEval_ReleaseLock(); /* Drop lock grabbed by InitThreads */
-
+#ifdef HAVE_PTHREAD_H
+ PyThreadState_Swap(NULL); /* We have to swap out the current thread else we get deadlocks */
+ PyEval_ReleaseLock(); /* Drop lock grabbed by InitThreads */
+#endif
DEBUG("mod_init done");
return 0;
failed:
- mod_error();
Py_XDECREF(radiusd_module);
+
+#ifdef HAVE_PTHREAD_H
+ PyEval_ReleaseLock();
+#endif
+
+ Pyx_BLOCK_THREADS
+ mod_error();
+ Pyx_UNBLOCK_THREADS
+
radiusd_module = NULL;
+
Py_Finalize();
return -1;
}
static int mod_destroy(void)
{
Pyx_BLOCK_THREADS
- Py_XDECREF(radiusd_module);
+ Py_XDECREF(radiusd_module);
Py_Finalize();
Pyx_UNBLOCK_THREADS
- return 0;
+
+ return 0;
}
/*
return -1;
}
-static rlm_rcode_t do_python(REQUEST *request, PyObject *pFunc, char const *funcname)
+#ifdef HAVE_PTHREAD_H
+/** Cleanup any thread local storage on pthread_exit()
+ */
+static void do_python_cleanup(void *arg)
+{
+ PyThreadState *my_thread_state = arg;
+
+ PyEval_AcquireLock();
+ PyThreadState_Swap(NULL); /* Not entirely sure this is needed */
+ PyThreadState_Clear(my_thread_state);
+ PyThreadState_Delete(my_thread_state);
+ PyEval_ReleaseLock();
+}
+#endif
+
+static rlm_rcode_t do_python(rlm_python_t *inst, REQUEST *request, PyObject *pFunc, char const *funcname, bool worker)
{
vp_cursor_t cursor;
VALUE_PAIR *vp;
int ret;
PyGILState_STATE gstate;
+ PyThreadState *prev_thread_state = NULL; /* -Wuninitialized */
+ memset(&gstate, 0, sizeof(gstate)); /* -Wuninitialized */
- /* Return with "noop" if the function is not defined. */
+ /* Return with "OK, continue" if the function is not defined. */
if (!pFunc)
return RLM_MODULE_NOOP;
+#ifdef HAVE_PTHREAD_H
+ gstate = PyGILState_Ensure();
+ if (worker) {
+ PyThreadState *my_thread_state;
+ my_thread_state = fr_thread_local_init(local_thread_state, do_python_cleanup);
+ if (!my_thread_state) {
+ my_thread_state = PyThreadState_New(inst->main_thread_state->interp);
+ RDEBUG3("Initialised new thread state %p", my_thread_state);
+ if (!my_thread_state) {
+ REDEBUG("Failed initialising local PyThreadState on first run");
+ PyGILState_Release(gstate);
+ return RLM_MODULE_FAIL;
+ }
+
+ ret = fr_thread_local_set(local_thread_state, my_thread_state);
+ if (ret != 0) {
+ REDEBUG("Failed storing PyThreadState in TLS: %s", fr_syserror(ret));
+ PyThreadState_Clear(my_thread_state);
+ PyThreadState_Delete(my_thread_state);
+ PyGILState_Release(gstate);
+ return RLM_MODULE_FAIL;
+ }
+ }
+ RDEBUG3("Using thread state %p", my_thread_state);
+ prev_thread_state = PyThreadState_Swap(my_thread_state); /* Swap in our local thread state */
+ }
+#endif
+
/* Default return value is "OK, continue" */
ret = RLM_MODULE_OK;
*/
tuplelen = 0;
if (request != NULL) {
- for (vp = paircursor(&cursor, &request->packet->vps);
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
tuplelen++;
}
}
- gstate = PyGILState_Ensure();
-
if (tuplelen == 0) {
Py_INCREF(Py_None);
pArgs = Py_None;
} else {
int i = 0;
- if ((pArgs = PyTuple_New(tuplelen)) == NULL)
- goto failed;
+ if ((pArgs = PyTuple_New(tuplelen)) == NULL) {
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
- for (vp = paircursor(&cursor, &request->packet->vps);
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
vp;
- vp = pairnext(&cursor), i++) {
+ vp = fr_cursor_next(&cursor), i++) {
PyObject *pPair;
/* The inside tuple has two only: */
- if ((pPair = PyTuple_New(2)) == NULL)
- goto failed;
+ if ((pPair = PyTuple_New(2)) == NULL) {
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
if (mod_populate_vptuple(pPair, vp) == 0) {
/* Put the tuple inside the container */
/* Call Python function. */
pRet = PyObject_CallFunctionObjArgs(pFunc, pArgs, NULL);
- if (!pRet)
- goto failed;
+ if (!pRet) {
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
if (!request)
- goto okay;
+ goto finish;
/*
* The function returns either:
if (PyTuple_GET_SIZE(pRet) != 3) {
ERROR("rlm_python:%s: tuple must be (return, replyTuple, configTuple)", funcname);
- goto failed;
+ ret = RLM_MODULE_FAIL;
+ goto finish;
}
pTupleInt = PyTuple_GET_ITEM(pRet, 0);
if (!PyInt_CheckExact(pTupleInt)) {
ERROR("rlm_python:%s: first tuple element not an integer", funcname);
- goto failed;
+ ret = RLM_MODULE_FAIL;
+ goto finish;
}
/* Now have the return value */
ret = PyInt_AsLong(pTupleInt);
} else {
/* Not tuple or None */
ERROR("rlm_python:%s: function did not return a tuple or None", funcname);
- goto failed;
+ ret = RLM_MODULE_FAIL;
+ goto finish;
}
-okay:
- Py_DECREF(pArgs);
- Py_DECREF(pRet);
- PyGILState_Release(gstate);
- return ret;
-
-failed:
- mod_error();
+finish:
Py_XDECREF(pArgs);
Py_XDECREF(pRet);
+
+#ifdef HAVE_PTHREAD_H
+ if (worker) {
+ PyThreadState_Swap(prev_thread_state);
+ }
PyGILState_Release(gstate);
+#endif
- return RLM_MODULE_FAIL;
+ return ret;
}
/*
{
if (*ob != NULL) {
Pyx_BLOCK_THREADS
- Py_DECREF(*ob);
+ Py_DECREF(*ob);
Pyx_UNBLOCK_THREADS
- *ob = NULL;
+ *ob = NULL;
}
}
{
rlm_python_t *inst = instance;
- if (mod_init() != 0) {
+ if (mod_init(inst) != 0) {
return -1;
}
* Call the instantiate function. No request. Use the
* return value.
*/
- return do_python(NULL, inst->instantiate.function,
- "instantiate");
+ return do_python(inst, NULL, inst->instantiate.function, "instantiate", false);
failed:
+ Pyx_BLOCK_THREADS
mod_error();
+ Pyx_UNBLOCK_THREADS
mod_instance_clear(inst);
return -1;
}
rlm_python_t *inst = instance;
int ret;
- ret = do_python(NULL, inst->detach.function, "detach");
+ /*
+ * Master should still have no thread state
+ */
+ ret = do_python(inst, NULL, inst->detach.function, "detach", false);
mod_instance_clear(inst);
+ dlclose(inst->libpython);
+
return ret;
}
-#define A(x) static rlm_rcode_t mod_##x(void *instance, REQUEST *request) { \
- return do_python(request, ((rlm_python_t *)instance)->x.function, #x); \
+#define A(x) static rlm_rcode_t CC_HINT(nonnull) mod_##x(void *instance, REQUEST *request) { \
+ return do_python((rlm_python_t *) instance, request, ((rlm_python_t *)instance)->x.function, #x, true);\
}
A(authenticate)
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
CPP C preprocessor
Use these variables to override the choices made by `configure' or to help
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
--header=FILE[:TEMPLATE]
- instantiate the configuration header FILE
+ instantiate the configuration header FILE
Configuration files:
$config_files
#include <freeradius-devel/rad_assert.h>
#include <fcntl.h>
-#include <limits.h>
#include "config.h"
*/
typedef struct nas_port {
uint32_t nasaddr;
- unsigned int port;
+ uint16_t port;
off_t offset;
struct nas_port *next;
} NAS_PORT;
typedef struct rlm_radutmp_t {
NAS_PORT *nas_port_list;
- char *filename;
- char *username;
+ char const *filename;
+ char const *username;
bool case_sensitive;
bool check_nas;
- int permission;
+ uint32_t permission;
bool caller_id_ok;
} rlm_radutmp_t;
static const CONF_PARSER module_config[] = {
- { "filename", PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED,
- offsetof(rlm_radutmp_t,filename), NULL, RADUTMP },
- { "username", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
- offsetof(rlm_radutmp_t,username), NULL, "%{User-Name}"},
- { "case_sensitive", PW_TYPE_BOOLEAN,
- offsetof(rlm_radutmp_t,case_sensitive), NULL, "yes"},
- { "check_with_nas", PW_TYPE_BOOLEAN,
- offsetof(rlm_radutmp_t,check_nas), NULL, "yes"},
- { "perm", PW_TYPE_INTEGER | PW_TYPE_DEPRECATED,
- offsetof(rlm_radutmp_t,permission), NULL, NULL },
- { "permissions", PW_TYPE_INTEGER,
- offsetof(rlm_radutmp_t,permission), NULL, "0644" },
- { "callerid", PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED,
- offsetof(rlm_radutmp_t,caller_id_ok), NULL, NULL },
- { "caller_id", PW_TYPE_BOOLEAN,
- offsetof(rlm_radutmp_t,caller_id_ok), NULL, "no" },
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED, rlm_radutmp_t, filename), RADUTMP },
+ { "username", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_radutmp_t, username), "%{User-Name}" },
+ { "case_sensitive", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_radutmp_t, case_sensitive), "yes" },
+ { "check_with_nas", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_radutmp_t, check_nas), "yes" },
+ { "perm", FR_CONF_OFFSET(PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, rlm_radutmp_t, permission), NULL },
+ { "permissions", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_radutmp_t, permission), "0644" },
+ { "callerid", FR_CONF_OFFSET(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, rlm_radutmp_t, caller_id_ok), NULL },
+ { "caller_id", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_radutmp_t, caller_id_ok), "no" },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
fd = open(filename, O_RDWR);
if (fd < 0) {
- REDEBUG("Error accessing file %s: %s", filename, strerror(errno));
+ REDEBUG("Error accessing file %s: %s", filename, fr_syserror(errno));
return RLM_MODULE_FAIL;
}
* Lock the utmp file, prefer lockf() over flock().
*/
if (rad_lockfd(fd, LOCK_LEN) < 0) {
- REDEBUG("Failed to acquire lock on file %s: %s", filename, strerror(errno));
+ REDEBUG("Failed to acquire lock on file %s: %s", filename, fr_syserror(errno));
close(fd);
return RLM_MODULE_FAIL;
}
u.time = t;
if (write(fd, &u, sizeof(u)) < 0) {
- REDEBUG("Failed writing: %s", strerror(errno));
+ REDEBUG("Failed writing: %s", fr_syserror(errno));
close(fd);
return RLM_MODULE_FAIL;
/*
* Lookup a NAS_PORT in the nas_port_list
*/
-static NAS_PORT *nas_port_find(NAS_PORT *nas_port_list, uint32_t nasaddr, unsigned int port)
+static NAS_PORT *nas_port_find(NAS_PORT *nas_port_list, uint32_t nasaddr, uint16_t port)
{
NAS_PORT *cl;
/*
* Store logins in the RADIUS utmp file.
*/
-static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
{
rlm_rcode_t rcode = RLM_MODULE_OK;
struct radutmp ut, u;
int protocol = -1;
time_t t;
int fd = -1;
- int port_seen = 0;
+ bool port_seen = false;
int off;
rlm_radutmp_t *inst = instance;
char ip_name[32]; /* 255.255.255.255 */
* Which type is this.
*/
if ((vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY)) == NULL) {
- RDEBUG("No Accounting-Status-Type record.");
+ RDEBUG("No Accounting-Status-Type record");
return RLM_MODULE_NOOP;
}
status = vp->vp_integer;
if (check1 == 0 || check2 == 0) {
break;
}
- INFO("rlm_radutmp: converting reboot records.");
+ INFO("rlm_radutmp: converting reboot records");
if (status == PW_STATUS_STOP)
status = PW_STATUS_ACCOUNTING_OFF;
if (status == PW_STATUS_START)
/*
* First, find the interesting attributes.
*/
- for (vp = paircursor(&cursor, &request->packet->vps);
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
if (!vp->da->vendor) switch (vp->da->attr) {
case PW_LOGIN_IP_HOST:
case PW_FRAMED_IP_ADDRESS:
break;
case PW_NAS_PORT:
ut.nas_port = vp->vp_integer;
- port_seen = 1;
+ port_seen = true;
break;
case PW_ACCT_DELAY_TIME:
ut.delay = vp->vp_integer;
*/
fd = open(filename, O_RDWR|O_CREAT, inst->permission);
if (fd < 0) {
- REDEBUG("Error accessing file %s: %s", filename, strerror(errno));
+ REDEBUG("Error accessing file %s: %s", filename, fr_syserror(errno));
rcode = RLM_MODULE_FAIL;
goto finish;
/*
* Lock the utmp file, prefer lockf() over flock().
*/
- rad_lockfd(fd, LOCK_LEN);
+ if (rad_lockfd(fd, LOCK_LEN) < 0) {
+ REDEBUG("Error acquiring lock on %s: %s", filename, fr_syserror(errno));
+ rcode = RLM_MODULE_FAIL;
+
+ goto finish;
+ }
/*
* Find the entry for this NAS / portno combination.
*/
if ((cache = nas_port_find(inst->nas_port_list, ut.nas_address, ut.nas_port)) != NULL) {
- lseek(fd, (off_t)cache->offset, SEEK_SET);
+ if (lseek(fd, (off_t)cache->offset, SEEK_SET) < 0) {
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
}
r = 0;
ut.type = P_LOGIN;
if (write(fd, &ut, sizeof(u)) < 0) {
- REDEBUG("Failed writing: %s", strerror(errno));
+ REDEBUG("Failed writing: %s", fr_syserror(errno));
rcode = RLM_MODULE_FAIL;
goto finish;
u.time = ut.time;
u.delay = ut.delay;
if (write(fd, &u, sizeof(u)) < 0) {
- REDEBUG("Failed writing: %s", strerror(errno));
+ REDEBUG("Failed writing: %s", fr_syserror(errno));
rcode = RLM_MODULE_FAIL;
goto finish;
* max. number of logins, do a second pass and validate all
* logins by querying the terminal server (using eg. SNMP).
*/
-static rlm_rcode_t mod_checksimul(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_checksimul(void *instance, REQUEST *request)
{
rlm_rcode_t rcode = RLM_MODULE_OK;
struct radutmp u;
/*
* Error accessing the file.
*/
- ERROR("rlm_radumtp: Error accessing file %s: %s", expanded, strerror(errno));
+ ERROR("rlm_radumtp: Error accessing file %s: %s", expanded, fr_syserror(errno));
rcode = RLM_MODULE_FAIL;
char session_id[sizeof(u.session_id) + 1];
char utmp_login[sizeof(u.login) + 1];
+ /* Guarantee string is NULL terminated */
+ u.session_id[sizeof(u.session_id) - 1] = '\0';
strlcpy(session_id, u.session_id, sizeof(session_id));
/*
module_t rlm_radutmp = {
RLM_MODULE_INIT,
"radutmp",
- RLM_TYPE_THREAD_UNSAFE | RLM_TYPE_CHECK_CONFIG_SAFE | RLM_TYPE_HUP_SAFE, /* type */
+ RLM_TYPE_THREAD_UNSAFE | RLM_TYPE_HUP_SAFE, /* type */
sizeof(rlm_radutmp_t),
module_config,
NULL, /* instantiation */
#define REALM_FORMAT_SUFFIX 1
typedef struct realm_config_t {
- int format;
- char *formatstring;
- char *delim;
- bool ignore_default;
- bool ignore_null;
- char *default_community;
- char *rp_realm;
- char *trust_router;
- unsigned int tr_port;
+ int format;
+ char const *format_string;
+ char const *delim;
+ bool ignore_default;
+ bool ignore_null;
+ char const *default_community;
+ char const *rp_realm;
+ char const *trust_router;
+ unsigned int tr_port;
} realm_config_t;
#define stringify(s) #s
static CONF_PARSER module_config[] = {
- { "format", PW_TYPE_STRING_PTR,
- offsetof(realm_config_t,formatstring), NULL, "suffix" },
- { "delimiter", PW_TYPE_STRING_PTR,
- offsetof(realm_config_t,delim), NULL, "@" },
- { "ignore_default", PW_TYPE_BOOLEAN,
- offsetof(realm_config_t,ignore_default), NULL, "no" },
- { "ignore_null", PW_TYPE_BOOLEAN,
- offsetof(realm_config_t,ignore_null), NULL, "no" },
- { "default_community", PW_TYPE_STRING_PTR,
- offsetof(realm_config_t,default_community), NULL, "none" },
- { "rp_realm", PW_TYPE_STRING_PTR,
- offsetof(realm_config_t,rp_realm), NULL, "none" },
- { "trust_router", PW_TYPE_STRING_PTR,
- offsetof(realm_config_t,trust_router), NULL, "none" },
- { "tr_port", PW_TYPE_INTEGER,
- offsetof(realm_config_t,tr_port), NULL, "0" },
- // offsetof(realm_config_t,tr_port), NULL, (stringify(TID_PORT)) },
+ { "format", FR_CONF_OFFSET(PW_TYPE_STRING, realm_config_t, format_string), "suffix" },
+ { "delimiter", FR_CONF_OFFSET(PW_TYPE_STRING, realm_config_t, delim), "@" },
+ { "ignore_default", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, realm_config_t, ignore_default), "no" },
+ { "ignore_null", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, realm_config_t, ignore_null), "no" },
+{ "default_community", FR_CONF_OFFSET(PW_TYPE_STRING,
+ realm_config_t,default_community), "none" },
+{ "rp_realm", FR_CONF_OFFSET(PW_TYPE_STRING,
+ realm_config_t,rp_realm), "none" },
+{ "trust_router", FR_CONF_OFFSET(PW_TYPE_STRING,
+ realm_config_t,trust_router), "none" },
+{ "tr_port", FR_CONF_OFFSET(PW_TYPE_INTEGER,
+ realm_config_t,tr_port), "0" },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
#endif
) {
- RDEBUG2("Proxy reply, or no User-Name. Ignoring.");
- return RLM_MODULE_OK;
+ RDEBUG2("Proxy reply, or no User-Name. Ignoring");
+ return RLM_MODULE_NOOP;
}
/*
*/
if (pairfind(request->packet->vps, PW_REALM, 0, TAG_ANY) != NULL ) {
- RDEBUG2("Request already has destination realm set. Ignoring.");
- return RLM_MODULE_OK;
+ RDEBUG2("Request already has destination realm set. Ignoring");
+ return RLM_MODULE_NOOP;
}
/*
* We will be modifing this later, so we want our own copy
* of it.
*/
- namebuf = talloc_strdup(request, request->username->vp_strvalue);
+ namebuf = talloc_typed_strdup(request, request->username->vp_strvalue);
username = namebuf;
switch(inst->format) {
}
if( inst->ignore_default &&
(strcmp(realm->name, "DEFAULT")) == 0) {
- RDEBUG2("Found DEFAULT, but skipping due to config.");
+ RDEBUG2("Found DEFAULT, but skipping due to config");
talloc_free(namebuf);
return RLM_MODULE_NOOP;
}
*
*/
if (request->username->da->attr != PW_STRIPPED_USER_NAME) {
- vp = radius_paircreate(request, &request->packet->vps,
+ vp = radius_paircreate(request->packet, &request->packet->vps,
PW_STRIPPED_USER_NAME, 0);
RDEBUG2("Adding Stripped-User-Name = \"%s\"", username);
} else {
RDEBUG2("Adding Realm = \"%s\"", realmname);
talloc_free(namebuf);
- realmname = username = NULL;
+ username = NULL;
/*
* Figure out what to do with the request.
default:
RDEBUG2("Unknown packet code %d\n",
request->packet->code);
- return RLM_MODULE_OK; /* don't do anything */
+ return RLM_MODULE_NOOP;
/*
* Perhaps accounting proxying was turned off.
*/
- case PW_ACCOUNTING_REQUEST:
+ case PW_CODE_ACCOUNTING_REQUEST:
if (!realm->acct_pool) {
- RDEBUG2("Accounting realm is LOCAL.");
+ RDEBUG2("Accounting realm is LOCAL");
return RLM_MODULE_OK;
}
break;
/*
* Perhaps authentication proxying was turned off.
*/
- case PW_AUTHENTICATION_REQUEST:
+ case PW_CODE_AUTHENTICATION_REQUEST:
if (!realm->auth_pool) {
- RDEBUG2("Authentication realm is LOCAL.");
+ RDEBUG2("Authentication realm is LOCAL");
return RLM_MODULE_OK;
}
break;
* Skip additional checks if it's not an accounting
* request.
*/
- if (request->packet->code != PW_ACCOUNTING_REQUEST) {
+ if (request->packet->code != PW_CODE_ACCOUNTING_REQUEST) {
*returnrealm = realm;
return RLM_MODULE_UPDATED;
}
/* initialize the trust router integration code */
if (tr_init() < 0)
return -1;
- if (strcasecmp(inst->formatstring, "suffix") == 0) {
-
+ if (strcasecmp(inst->format_string, "suffix") == 0) {
inst->format = REALM_FORMAT_SUFFIX;
- } else if (strcasecmp(inst->formatstring, "prefix") == 0) {
+ } else if (strcasecmp(inst->format_string, "prefix") == 0) {
inst->format = REALM_FORMAT_PREFIX;
} else {
cf_log_err_cs(conf, "Invalid value \"%s\" for format",
- inst->formatstring);
+ inst->format_string);
return -1;
}
*
* This should very nearly duplicate the old proxy_send() code
*/
-static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
{
rlm_rcode_t rcode;
REALM *realm;
* This does the exact same thing as the mod_authorize, it's just called
* differently.
*/
-static rlm_rcode_t mod_preacct(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_preacct(void *instance, REQUEST *request)
{
int rcode;
REALM *realm;
* CoA realms via Operator-Name. Because the realm isn't in a
* User-Name, concepts like "prefix" and "suffix' don't matter.
*/
-static rlm_rcode_t realm_recv_coa(UNUSED void *instance, REQUEST *request)
+static rlm_rcode_t mod_realm_recv_coa(UNUSED void *instance, REQUEST *request)
{
VALUE_PAIR *vp;
REALM *realm;
if (pairfind(request->packet->vps, PW_REALM, 0, TAG_ANY) != NULL) {
- RDEBUG2("Request already has destination realm set. Ignoring.");
- return RLM_MODULE_OK;
+ RDEBUG2("Request already has destination realm set. Ignoring");
+ return RLM_MODULE_NOOP;
}
vp = pairfind(request->packet->vps, PW_OPERATOR_NAME, 0, TAG_ANY);
if (!realm->coa_pool) {
- RDEBUG2("CoA realm is LOCAL.");
+ RDEBUG2("CoA realm is LOCAL");
return RLM_MODULE_OK;
}
module_t rlm_realm = {
RLM_MODULE_INIT,
"realm",
- RLM_TYPE_CHECK_CONFIG_SAFE | RLM_TYPE_HUP_SAFE, /* type */
+ RLM_TYPE_HUP_SAFE, /* type */
sizeof(struct realm_config_t),
module_config,
mod_instantiate, /* instantiation */
NULL, /* post-proxy */
NULL /* post-auth */
#ifdef WITH_COA
- , realm_recv_coa, /* recv-coa */
+ , mod_realm_recv_coa, /* recv-coa */
NULL /* send-coa */
#endif
},
};
+
}
static fr_tls_server_conf_t *construct_tls( TIDC_INSTANCE *inst,
- home_server *hs,
+ home_server_t *hs,
TID_SRVR_BLK *server)
{
fr_tls_server_conf_t *tls = talloc_zero( hs, fr_tls_server_conf_t);
UNUSED TID_REQ *req, TID_RESP *resp,
void *cookie)
{
- home_server *hs = NULL;
+ home_server_t *hs = NULL;
TID_SRVR_BLK *server;
home_pool_t *pool = NULL;
REALM *nr = NULL;
pool = home_pool_byname(home_pool_name, HOME_TYPE_AUTH);
if (pool == NULL) {
size_t i = 0;
- pool = rad_malloc(sizeof(*pool) + num_servers *sizeof(home_server *));
+ pool = talloc_zero_size(NULL, sizeof(*pool) + num_servers *sizeof(home_server_t *));
if (pool == NULL) goto error;
- memset(pool, 0, sizeof(*pool));
pool->type = HOME_POOL_CLIENT_PORT_BALANCE;
pool->server_type = HOME_TYPE_AUTH;
pool->name = strdup(home_pool_name);
} else {
char nametemp[INET_ADDRSTRLEN];
inet_ntop(home_server_ip.af, &home_server_ip.ipaddr, nametemp, sizeof(nametemp));
- hs = talloc_zero(NULL, home_server);
+ hs = talloc_zero(pool, home_server_t);
if (!hs) return;
- memset(hs, 0, sizeof(*hs));
hs->type = HOME_TYPE_AUTH;
hs->ipaddr = home_server_ip;
hs->src_ipaddr.af = home_server_ip.af;
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-redis-include-dir=DIR
- Directory where the redis includes may be found
+ Directory where the redis includes may be found
--with-redis-lib-dir=DIR
- Directory where the redis libraries may be found
+ Directory where the redis libraries may be found
--with-redis-dir=DIR Base directory where redis is installed
Some influential environment variables:
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
if test x$with_rlm_redis != xno; then
- redis_include_dir=
+ redis_include_dir=
# Check whether --with-redis-include-dir was given.
if test "${with_redis_include_dir+set}" = set; then :
fi
- redis_lib_dir=
+ redis_lib_dir=
# Check whether --with-redis-lib-dir was given.
if test "${with_redis_lib_dir+set}" = set; then :
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=hiredis/hiredis.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lhiredis"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lhiredis"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libhiredis${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libhiredis.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
#include "rlm_redis.h"
static const CONF_PARSER module_config[] = {
- { "hostname", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(REDIS_INST, hostname), NULL, NULL},
- { "server", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
- offsetof(REDIS_INST, hostname), NULL, NULL},
- { "port", PW_TYPE_INTEGER,
- offsetof(REDIS_INST, port), NULL, "6379"},
- { "database", PW_TYPE_INTEGER,
- offsetof(REDIS_INST, database), NULL, "0"},
- { "password", PW_TYPE_STRING_PTR,
- offsetof(REDIS_INST, password), NULL, NULL},
+ { "hostname", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, REDIS_INST, hostname), NULL },
+ { "server", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, REDIS_INST, hostname), NULL },
+ { "port", FR_CONF_OFFSET(PW_TYPE_SHORT, REDIS_INST, port), "6379" },
+ { "database", FR_CONF_OFFSET(PW_TYPE_INTEGER, REDIS_INST, database), "0" },
+ { "password", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, REDIS_INST, password), NULL },
{ NULL, -1, 0, NULL, NULL} /* end the list */
};
REDIS_INST *inst = ctx;
REDISSOCK *dissocket = NULL;
redisContext *conn;
+ redisReply *reply = NULL;
char buffer[1024];
conn = redisConnect(inst->hostname, inst->port);
if (conn->err) return NULL;
if (inst->password) {
- redisReply *reply = NULL;
-
snprintf(buffer, sizeof(buffer), "AUTH %s", inst->password);
reply = redisCommand(conn, buffer);
}
if (inst->database) {
- redisReply *reply = NULL;
-
snprintf(buffer, sizeof(buffer), "SELECT %d", inst->database);
reply = redisCommand(conn, buffer);
char buffer[21];
dissocket = fr_connection_get(inst->pool);
- if (!dissocket) {
- ERROR("rlm_redis (%s): redis_get_socket() failed",
- inst->xlat_name);
-
- return -1;
- }
+ if (!dissocket) return -1;
/* Query failed for some reason, release socket and return */
if (rlm_redis_query(&dissocket, inst, fmt, request) < 0) {
typedef struct rlm_redis_t REDIS_INST;
typedef struct rlm_redis_t {
- char const *xlat_name;
+ char const *xlat_name;
- char *hostname;
- int port;
- int database;
- char *password;
- fr_connection_pool_t *pool;
+ char const *hostname;
+ uint16_t port;
+ uint32_t database;
+ char const *password;
+ fr_connection_pool_t *pool;
int (*redis_query)(REDISSOCK **dissocket_p, REDIS_INST *inst, char const *query, REQUEST *request);
int (*redis_finish_query)(REDISSOCK *dissocket);
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-redis-include-dir=DIR
- Directory where the redis includes may be found
+ Directory where the redis includes may be found
--with-redis-lib-dir=DIR
- Directory where the redis libraries may be found
+ Directory where the redis libraries may be found
--with-redis-dir=DIR Base directory where redis is installed
Some influential environment variables:
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
if test x$with_rlm_rediswho != xno; then
- redis_include_dir=
+ redis_include_dir=
# Check whether --with-redis-include-dir was given.
if test "${with_redis_include_dir+set}" = set; then :
fi
- redis_lib_dir=
+ redis_lib_dir=
# Check whether --with-redis-lib-dir was given.
if test "${with_redis_lib_dir+set}" = set; then :
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=hiredis/hiredis.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lhiredis"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lhiredis"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libhiredis${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libhiredis.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
char const *xlat_name;
CONF_SECTION *cs;
- char *redis_instance_name;
+ char const *redis_instance_name;
REDIS_INST *redis_inst;
/*
} rlm_rediswho_t;
static CONF_PARSER module_config[] = {
- { "redis-instance-name", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_rediswho_t, redis_instance_name), NULL, NULL},
- { "redis_module_instance", PW_TYPE_STRING_PTR,
- offsetof(rlm_rediswho_t, redis_instance_name), NULL, "redis"},
+ { "redis-instance-name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_rediswho_t, redis_instance_name), NULL },
+ { "redis_module_instance", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_rediswho_t, redis_instance_name), "redis" },
- { "trim-count", PW_TYPE_INTEGER | PW_TYPE_DEPRECATED,
- offsetof(rlm_rediswho_t, trim_count), NULL, NULL},
- { "trim_count", PW_TYPE_INTEGER,
- offsetof(rlm_rediswho_t, trim_count), NULL, "-1"},
+ { "trim-count", FR_CONF_OFFSET(PW_TYPE_SIGNED | PW_TYPE_DEPRECATED, rlm_rediswho_t, trim_count), NULL },
+ { "trim_count", FR_CONF_OFFSET(PW_TYPE_SIGNED, rlm_rediswho_t, trim_count), "-1" },
{ NULL, -1, 0, NULL, NULL}
};
return RLM_MODULE_OK;
}
-static rlm_rcode_t mod_accounting(void * instance, REQUEST * request)
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void * instance, REQUEST * request)
{
rlm_rcode_t rcode;
VALUE_PAIR * vp;
vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY);
if (!vp) {
- RDEBUG("Could not find account status type in packet.");
+ RDEBUG("Could not find account status type in packet");
return RLM_MODULE_NOOP;
}
}
dissocket = fr_connection_get(inst->redis_inst->pool);
- if (!dissocket) {
- RDEBUG("cannot allocate redis connection");
- return RLM_MODULE_FAIL;
- }
+ if (!dissocket) return RLM_MODULE_FAIL;
insert = cf_pair_value(cf_pair_find(cs, "insert"));
trim = cf_pair_value(cf_pair_find(cs, "trim"));
int rcode = RLM_MODULE_NOOP;
VALUE_PAIR *vp, **vps;
vp_cursor_t cursor;
- home_server *home;
+ home_server_t *home;
REALM *realm;
home_pool_t *pool;
RADIUS_PACKET *packet = NULL;
* Send as many packets as necessary to different
* destinations.
*/
- paircursor(&cursor, &request->config_items);
- while ((vp = pairfindnext(&cursor, PW_REPLICATE_TO_REALM, 0, TAG_ANY))) {
+ fr_cursor_init(&cursor, &request->config_items);
+ while ((vp = fr_cursor_next_by_num(&cursor, PW_REPLICATE_TO_REALM, 0, TAG_ANY))) {
realm = realm_find2(vp->vp_strvalue);
if (!realm) {
REDEBUG2("Cannot Replicate to unknown realm \"%s\"", vp->vp_strvalue);
cleanup(packet);
return RLM_MODULE_FAIL;
- case PW_AUTHENTICATION_REQUEST:
+ case PW_CODE_AUTHENTICATION_REQUEST:
pool = realm->auth_pool;
break;
#ifdef WITH_ACCOUNTING
- case PW_ACCOUNTING_REQUEST:
+ case PW_CODE_ACCOUNTING_REQUEST:
pool = realm->acct_pool;
break;
#endif
#ifdef WITH_COA
- case PW_COA_REQUEST:
- case PW_DISCONNECT_REQUEST:
+ case PW_CODE_COA_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
pool = realm->acct_pool;
break;
#endif
* For CHAP, create the CHAP-Challenge if
* it doesn't exist.
*/
- if ((code == PW_AUTHENTICATION_REQUEST) &&
+ if ((code == PW_CODE_AUTHENTICATION_REQUEST) &&
(pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY) != NULL) &&
(pairfind(request->packet->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY) == NULL)) {
uint8_t *p;
- vp = radius_paircreate(request, &packet->vps, PW_CHAP_CHALLENGE, 0);
+ vp = radius_paircreate(packet, &packet->vps, PW_CHAP_CHALLENGE, 0);
vp->length = AUTH_VECTOR_LEN;
vp->vp_octets = p = talloc_array(vp, uint8_t, vp->length);
memcpy(p, request->packet->vector, AUTH_VECTOR_LEN);
}
#endif
-static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
{
return replicate_packet(instance, request, PAIR_LIST_REQUEST, request->packet->code);
}
-static rlm_rcode_t mod_preaccounting(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_preaccounting(void *instance, REQUEST *request)
{
return replicate_packet(instance, request, PAIR_LIST_REQUEST, request->packet->code);
}
-static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
-{
- return replicate_packet(instance, request, PAIR_LIST_REPLY, request->reply->code);
-}
-
#ifdef WITH_PROXY
-static rlm_rcode_t mod_pre_proxy(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_pre_proxy(void *instance, REQUEST *request)
{
return replicate_packet(instance, request, PAIR_LIST_PROXY_REQUEST, request->proxy->code);
}
-
-static rlm_rcode_t mod_post_proxy(void *instance, REQUEST *request)
-{
- return replicate_packet(instance, request, PAIR_LIST_PROXY_REPLY, request->proxy_reply->code);
-}
#endif
-static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request)
-{
- return replicate_packet(instance, request, PAIR_LIST_REPLY, request->reply->code);
-}
-
#ifdef WITH_COA
-static rlm_rcode_t mod_recv_coa(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_recv_coa(void *instance, REQUEST *request)
{
return replicate_packet(instance, request, PAIR_LIST_REQUEST, request->packet->code);
}
NULL, /* authentication */
mod_authorize, /* authorization */
mod_preaccounting, /* preaccounting */
- mod_accounting, /* accounting */
+ NULL, /* accounting */
NULL, /* checksimul */
#ifdef WITH_PROXY
mod_pre_proxy, /* pre-proxy */
- mod_post_proxy, /* post-proxy */
+ NULL, /* post-proxy */
#else
NULL, NULL,
#endif
- mod_post_auth /* post-auth */
+ NULL /* post-auth */
#ifdef WITH_COA
, mod_recv_coa, /* coa-request */
NULL
/* config.h.in. Generated from configure.ac by autoheader. */
-/* Define to 1 if you have the <inttypes.h> header file. */
-#undef HAVE_INTTYPES_H
-
/* Build with JSON support from json-c */
#undef HAVE_JSON
-/* Define to 1 if you have the <json/json.h> header file. */
-#undef HAVE_JSON_JSON_H
+/* Define to 1 if you have the `json_c_version' function. */
+#undef HAVE_JSON_C_VERSION
+
+/* Define to 1 if you have the `json_type_to_name' function. */
+#undef HAVE_JSON_TYPE_TO_NAME
/* Define to 1 if you have a functional curl library. */
#undef HAVE_LIBCURL
-/* Define to 1 if you have the <memory.h> header file. */
-#undef HAVE_MEMORY_H
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#undef HAVE_STDINT_H
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#undef HAVE_STDLIB_H
-
-/* Define to 1 if you have the <strings.h> header file. */
-#undef HAVE_STRINGS_H
-
-/* Define to 1 if you have the <string.h> header file. */
-#undef HAVE_STRING_H
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#undef HAVE_SYS_STAT_H
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#undef HAVE_SYS_TYPES_H
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#undef HAVE_UNISTD_H
-
/* Defined if libcurl supports AsynchDNS */
#undef LIBCURL_FEATURE_ASYNCHDNS
/* Define to the version of this package. */
#undef PACKAGE_VERSION
-/* Define to 1 if you have the ANSI C header files. */
-#undef STDC_HEADERS
-
/* Define curl_free() as free() if our version of curl lacks curl_free. */
#undef curl_free
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-libcurl=PREFIX look for the curl library in PREFIX/lib and headers
- in PREFIX/include
+ in PREFIX/include
--with-jsonc-include-dir=DIR
- Directory where the json-c includes may be found
+ Directory where the json-c includes may be found
--with-jsonc-lib-dir=DIR
- Directory where the json-c libraries may be found
+ Directory where the json-c libraries may be found
--with-jsonc-dir=DIR Base directory where json-c is installed
Some influential environment variables:
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
CPP C preprocessor
Use these variables to override the choices made by `configure' or to help
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
_libcurl_try_link=yes
if test -d "$_libcurl_with" ; then
- LIBCURL_CPPFLAGS="-I$withval/include"
- _libcurl_ldflags="-L$withval/lib"
- # Extract the first word of "curl-config", so it can be a program name with args.
+ LIBCURL_CPPFLAGS="-I$withval/include"
+ _libcurl_ldflags="-L$withval/lib"
+ # Extract the first word of "curl-config", so it can be a program name with args.
set dummy curl-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
else
- # Extract the first word of "curl-config", so it can be a program name with args.
+ # Extract the first word of "curl-config", so it can be a program name with args.
set dummy curl-config; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
fi
if test x$_libcurl_config != "x" ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the version of libcurl" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the version of libcurl" >&5
$as_echo_n "checking for the version of libcurl... " >&6; }
if ${libcurl_cv_lib_curl_version+:} false; then :
$as_echo_n "(cached) " >&6
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libcurl_cv_lib_curl_version" >&5
$as_echo "$libcurl_cv_lib_curl_version" >&6; }
- _libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse`
- _libcurl_wanted=`echo 7.19.1 | $_libcurl_version_parse`
+ _libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse`
+ _libcurl_wanted=`echo 7.19.1 | $_libcurl_version_parse`
- if test $_libcurl_wanted -gt 0 ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libcurl >= version 7.19.1" >&5
+ if test $_libcurl_wanted -gt 0 ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libcurl >= version 7.19.1" >&5
$as_echo_n "checking for libcurl >= version 7.19.1... " >&6; }
if ${libcurl_cv_lib_version_ok+:} false; then :
$as_echo_n "(cached) " >&6
else
- if test $_libcurl_version -ge $_libcurl_wanted ; then
- libcurl_cv_lib_version_ok=yes
- else
- libcurl_cv_lib_version_ok=no
- fi
+ if test $_libcurl_version -ge $_libcurl_wanted ; then
+ libcurl_cv_lib_version_ok=yes
+ else
+ libcurl_cv_lib_version_ok=no
+ fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libcurl_cv_lib_version_ok" >&5
$as_echo "$libcurl_cv_lib_version_ok" >&6; }
- fi
-
- if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then
- if test x"$LIBCURL_CPPFLAGS" = "x" ; then
- LIBCURL_CPPFLAGS=`$_libcurl_config --cflags`
- fi
- if test x"$LIBCURL" = "x" ; then
- LIBCURL=`$_libcurl_config --libs`
-
- # This is so silly, but Apple actually has a bug in their
- # curl-config script. Fixed in Tiger, but there are still
- # lots of Panther installs around.
- case "${host}" in
- powerpc-apple-darwin7*)
- LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'`
- ;;
- esac
- fi
-
- # All curl-config scripts support --feature
- _libcurl_features=`$_libcurl_config --feature`
-
- # Is it modern enough to have --protocols? (7.12.4)
- if test $_libcurl_version -ge 461828 ; then
- _libcurl_protocols=`$_libcurl_config --protocols`
- fi
- else
- _libcurl_try_link=no
- fi
-
- unset _libcurl_wanted
+ fi
+
+ if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then
+ if test x"$LIBCURL_CPPFLAGS" = "x" ; then
+ LIBCURL_CPPFLAGS=`$_libcurl_config --cflags`
+ fi
+ if test x"$LIBCURL" = "x" ; then
+ LIBCURL=`$_libcurl_config --libs`
+
+ # This is so silly, but Apple actually has a bug in their
+ # curl-config script. Fixed in Tiger, but there are still
+ # lots of Panther installs around.
+ case "${host}" in
+ powerpc-apple-darwin7*)
+ LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'`
+ ;;
+ esac
+ fi
+
+ # All curl-config scripts support --feature
+ _libcurl_features=`$_libcurl_config --feature`
+
+ # Is it modern enough to have --protocols? (7.12.4)
+ if test $_libcurl_version -ge 461828 ; then
+ _libcurl_protocols=`$_libcurl_config --protocols`
+ fi
+ else
+ _libcurl_try_link=no
+ fi
+
+ unset _libcurl_wanted
fi
if test $_libcurl_try_link = yes ; then
- # we didn't find curl-config, so let's see if the user-supplied
- # link line (or failing that, "-lcurl") is enough.
- LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"}
+ # we didn't find curl-config, so let's see if the user-supplied
+ # link line (or failing that, "-lcurl") is enough.
+ LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"}
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether libcurl is usable" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether libcurl is usable" >&5
$as_echo_n "checking whether libcurl is usable... " >&6; }
if ${libcurl_cv_lib_curl_usable+:} false; then :
$as_echo_n "(cached) " >&6
else
- _libcurl_save_cppflags=$CPPFLAGS
- CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS"
- _libcurl_save_libs=$LIBS
- LIBS="$LIBCURL $LIBS"
+ _libcurl_save_cppflags=$CPPFLAGS
+ CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS"
+ _libcurl_save_libs=$LIBS
+ LIBS="$LIBCURL $LIBS"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <curl/curl.h>
int
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
- CPPFLAGS=$_libcurl_save_cppflags
- LIBS=$_libcurl_save_libs
- unset _libcurl_save_cppflags
- unset _libcurl_save_libs
+ CPPFLAGS=$_libcurl_save_cppflags
+ LIBS=$_libcurl_save_libs
+ unset _libcurl_save_cppflags
+ unset _libcurl_save_libs
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libcurl_cv_lib_curl_usable" >&5
$as_echo "$libcurl_cv_lib_curl_usable" >&6; }
- if test $libcurl_cv_lib_curl_usable = yes ; then
+ if test $libcurl_cv_lib_curl_usable = yes ; then
- # Does curl_free() exist in this version of libcurl?
- # If not, fake it with free()
+ # Does curl_free() exist in this version of libcurl?
+ # If not, fake it with free()
- _libcurl_save_cppflags=$CPPFLAGS
- CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS"
- _libcurl_save_libs=$LIBS
- LIBS="$LIBS $LIBCURL"
+ _libcurl_save_cppflags=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS"
+ _libcurl_save_libs=$LIBS
+ LIBS="$LIBS $LIBCURL"
- ac_fn_c_check_func "$LINENO" "curl_free" "ac_cv_func_curl_free"
+ ac_fn_c_check_func "$LINENO" "curl_free" "ac_cv_func_curl_free"
if test "x$ac_cv_func_curl_free" = xyes; then :
else
fi
- CPPFLAGS=$_libcurl_save_cppflags
- LIBS=$_libcurl_save_libs
- unset _libcurl_save_cppflags
- unset _libcurl_save_libs
+ CPPFLAGS=$_libcurl_save_cppflags
+ LIBS=$_libcurl_save_libs
+ unset _libcurl_save_cppflags
+ unset _libcurl_save_libs
$as_echo "#define HAVE_LIBCURL 1" >>confdefs.h
- for _libcurl_feature in $_libcurl_features ; do
- cat >>confdefs.h <<_ACEOF
+ for _libcurl_feature in $_libcurl_features ; do
+ cat >>confdefs.h <<_ACEOF
#define `$as_echo "libcurl_feature_$_libcurl_feature" | $as_tr_cpp` 1
_ACEOF
- eval `$as_echo "libcurl_feature_$_libcurl_feature" | $as_tr_sh`=yes
- done
+ eval `$as_echo "libcurl_feature_$_libcurl_feature" | $as_tr_sh`=yes
+ done
- if test "x$_libcurl_protocols" = "x" ; then
+ if test "x$_libcurl_protocols" = "x" ; then
- # We don't have --protocols, so just assume that all
- # protocols are available
- _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP"
+ # We don't have --protocols, so just assume that all
+ # protocols are available
+ _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP"
- if test x$libcurl_feature_SSL = xyes ; then
- _libcurl_protocols="$_libcurl_protocols HTTPS"
+ if test x$libcurl_feature_SSL = xyes ; then
+ _libcurl_protocols="$_libcurl_protocols HTTPS"
- # FTPS wasn't standards-compliant until version
- # 7.11.0 (0x070b00 == 461568)
- if test $_libcurl_version -ge 461568; then
- _libcurl_protocols="$_libcurl_protocols FTPS"
- fi
- fi
+ # FTPS wasn't standards-compliant until version
+ # 7.11.0 (0x070b00 == 461568)
+ if test $_libcurl_version -ge 461568; then
+ _libcurl_protocols="$_libcurl_protocols FTPS"
+ fi
+ fi
- # RTSP, IMAP, POP3 and SMTP were added in
- # 7.20.0 (0x071400 == 463872)
- if test $_libcurl_version -ge 463872; then
- _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP"
- fi
- fi
+ # RTSP, IMAP, POP3 and SMTP were added in
+ # 7.20.0 (0x071400 == 463872)
+ if test $_libcurl_version -ge 463872; then
+ _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP"
+ fi
+ fi
- for _libcurl_protocol in $_libcurl_protocols ; do
- cat >>confdefs.h <<_ACEOF
+ for _libcurl_protocol in $_libcurl_protocols ; do
+ cat >>confdefs.h <<_ACEOF
#define `$as_echo "libcurl_protocol_$_libcurl_protocol" | $as_tr_cpp` 1
_ACEOF
- eval `$as_echo "libcurl_protocol_$_libcurl_protocol" | $as_tr_sh`=yes
- done
- else
- unset LIBCURL
- unset LIBCURL_CPPFLAGS
- fi
+ eval `$as_echo "libcurl_protocol_$_libcurl_protocol" | $as_tr_sh`=yes
+ done
+ else
+ unset LIBCURL
+ unset LIBCURL_CPPFLAGS
+ fi
fi
unset _libcurl_try_link
no)
as_fn_error $? "Need jsonc-include-dir" "$LINENO" 5
;;
- yes)
+ yes)
;;
*)
- jsonc_include_dir="$withval"
+ jsonc_include_dir="$withval"
;;
esac
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=json/json.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-ljson-c"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-ljson-c"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libjson-c${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libjson-c.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$ac_cv_lib_json_c_json_c_version" != "xyes"
then
- have_json="no"
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: json-c libraries not found. Use --with-jsonc-lib-dir=<path>." >&5
-$as_echo "$as_me: WARNING: json-c libraries not found. Use --with-jsonc-lib-dir=<path>." >&2;}
+
+
+sm_lib_safe=`echo "json" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "json_tokener_new" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+smart_lib=
+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 json_tokener_new in -ljson in $try" >&5
+$as_echo_n "checking for json_tokener_new in -ljson in $try... " >&6; }
+ LIBS="-L$try -ljson $old_LIBS -Wl,-rpath,$try"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char json_tokener_new();
+int
+main ()
+{
+json_tokener_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-L$try -ljson -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"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for json_tokener_new in -ljson" >&5
+$as_echo_n "checking for json_tokener_new in -ljson... " >&6; }
+ LIBS="-ljson $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char json_tokener_new();
+int
+main ()
+{
+json_tokener_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ljson"
+ { $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=libjson${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=libjson.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 json_tokener_new in -ljson in $try" >&5
+$as_echo_n "checking for json_tokener_new in -ljson in $try... " >&6; }
+ LIBS="-L$try -ljson $old_LIBS -Wl,-rpath,$try"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char json_tokener_new();
+int
+main ()
+{
+json_tokener_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-L$try -ljson -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"
+fi
+
+if test "x$smart_lib" != "x"; then
+ eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
+ LIBS="$smart_lib $old_LIBS"
+ SMART_LIBS="$smart_lib $SMART_LIBS"
+fi
+
+ if test "x$ac_cv_lib_json_json_tokener_new" != "xyes"
+ then
+ have_json="no"
+ fi
fi
if test "x$have_json" = "xyes"; then
+ LDFLAGS="$SMART_LIBS"
+
+ for ac_func in \
+ json_c_version \
+ json_type_to_name
+
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
$as_echo "#define HAVE_JSON 1" >>confdefs.h
else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: json-c libraries not found. Use --with-jsonc-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: json-c libraries not found. Use --with-jsonc-lib-dir=<path>." >&2;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently building without JSON support. requires: json-c" >&5
$as_echo "$as_me: WARNING: silently building without JSON support. requires: json-c" >&2;}
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
--header=FILE[:TEMPLATE]
- instantiate the configuration header FILE
+ instantiate the configuration header FILE
Configuration files:
$config_files
fi
+
LIBCURL_CHECK_CONFIG([], [7.19.1])
- if test "x$libcurl_cv_lib_version_ok" != "xyes"; then
+ if test "x$libcurl_cv_lib_version_ok" != "xyes"; then
fail="$fail libcurl >= 7.19.2"
elif test "x$libcurl_cv_lib_curl_usable" != "xyes"; then
fail="$fail libcurl"
- else
+ else
if test x$libcurl_protocol_HTTP != xyes; then
fail="$fail libcurl_protocol_http"
fi
-
+
if test x$libcurl_protocol_HTTPS != xyes || test x$libcurl_feature_SSL != xyes; then
AC_MSG_WARN([silently building without HTTPS support. requires: libcurl_protocol_https.])
fi
no)
AC_MSG_ERROR(Need jsonc-include-dir)
;;
- yes)
+ yes)
;;
*)
- jsonc_include_dir="$withval"
+ jsonc_include_dir="$withval"
;;
esac])
have_json="no"
AC_MSG_WARN([json-c headers not found. Use --with-jsonc-include-dir=<path>.])
fi
-
+
dnl ############################################################
dnl # Check for json-c libraries
dnl ############################################################
smart_try_dir="$jsonc_lib_dir"
+ dnl # Use a json-c specific function which is only
+ dnl # available in newer versions.
FR_SMART_CHECK_LIB([json-c], [json_c_version])
if test "x$ac_cv_lib_json_c_json_c_version" != "xyes"
then
- have_json="no"
- AC_MSG_WARN([json-c libraries not found. Use --with-jsonc-lib-dir=<path>.])
+ dnl # Use a function which is included in legacy versions
+ dnl # but which may be available in other json libraries
+ FR_SMART_CHECK_LIB([json], [json_tokener_new])
+ if test "x$ac_cv_lib_json_json_tokener_new" != "xyes"
+ then
+ have_json="no"
+ fi
fi
-
+
if test "x$have_json" = "xyes"; then
+ dnl # Ensure we use the library we just found the rest of the checks
+ LDFLAGS="$SMART_LIBS"
+
+ dnl # Add any optional functions here
+ AC_CHECK_FUNCS(\
+ json_c_version \
+ json_type_to_name
+ )
+
AC_DEFINE([HAVE_JSON],[1],[Build with JSON support from json-c])
else
+ AC_MSG_WARN([json-c libraries not found. Use --with-jsonc-lib-dir=<path>.])
AC_MSG_WARN([silently building without JSON support. requires: json-c])
fi
AC_SUBST(targetname)
AC_OUTPUT(all.mk)
+
use HTTP::Status;
use HTTP::Response;
-my $d = new HTTP::Daemon(LocalAddr => '127.0.0.1', LocalPort => 9090);
-print "Please contact me at: <URL:", $d->url, ">\n";
-while (my $c = $d->accept) {
- while (my $r = $c->get_request) {
- print "Got " . $r->method . " request\n";
- if ($r->method eq 'POST' and $r->url->path eq "/") {
+# Required else we get weird issues ports being bound after the
+# daemon exits.
+my $daemon;
+my $client;
+
+sub close_client {
+ if (defined $client) {
+ $client->shutdown(2);
+ $client->close();
+ }
+}
+
+sub close_daemon {
+ if (defined $daemon) {
+ print "Closing daemon socket\n";
+ $daemon->shutdown(2);
+ $daemon->close();
+ }
+ close_client();
+}
+
+$SIG{'INT'} = \&close_daemon;
+$SIG{'QUIT'} = \&close_daemon;
+$SIG{'PIPE'} = \&close_client;
+
+$daemon = new HTTP::Daemon(ReuseAddr => 1, LocalAddr => '127.0.0.1', LocalPort => 9090);
+if (!defined $daemon) {
+ die "Error opening socket: $!";
+}
+
+print "Please contact me at: ", $daemon->url, "\n";
+while ($client = $daemon->accept) {
+ $client->timeout(1);
+ while (my $r = $client->get_request) {
+ print "Got " . $r->method . " request for " . $r->url->path . "\n";
+ if ((($r->method eq 'POST') or ($r->method eq 'GET')) and $r->url->path eq "/") {
my $resp = HTTP::Response->new( '200', 'OK' );
- $resp->header("Content-Type" => "application/x-www-form-urlencoded");
- $resp->content("control:Cleartext-Password=password&reply:Reply-Message=testing123");
+ $resp->header("Content-Type" => "application/json");
+ $resp->content("{\"control:Cleartext-Password\":\"testing123\",\"reply:Reply-Message\":\"Hello from demo.pl\"}");
- $c->send_response($resp);
+ $client->send_response($resp);
} else {
- $c->send_error(RC_FORBIDDEN)
+ $client->send_error(RC_FORBIDDEN)
}
}
- $c->close;
- undef($c);
+
+ close_client();
+ undef($client);
}
_libcurl_try_link=yes
if test -d "$_libcurl_with" ; then
- LIBCURL_CPPFLAGS="-I$withval/include"
- _libcurl_ldflags="-L$withval/lib"
- AC_PATH_PROG([_libcurl_config],[curl-config],[],
- ["$withval/bin"])
+ LIBCURL_CPPFLAGS="-I$withval/include"
+ _libcurl_ldflags="-L$withval/lib"
+ AC_PATH_PROG([_libcurl_config],[curl-config],[],
+ ["$withval/bin"])
else
- AC_PATH_PROG([_libcurl_config],[curl-config],[],[$PATH])
+ AC_PATH_PROG([_libcurl_config],[curl-config],[],[$PATH])
fi
if test x$_libcurl_config != "x" ; then
- AC_CACHE_CHECK([for the version of libcurl],
- [libcurl_cv_lib_curl_version],
- [libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $[]2}'`])
-
- _libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse`
- _libcurl_wanted=`echo ifelse([$2],,[0],[$2]) | $_libcurl_version_parse`
-
- if test $_libcurl_wanted -gt 0 ; then
- AC_CACHE_CHECK([for libcurl >= version $2],
- [libcurl_cv_lib_version_ok],
- [
- if test $_libcurl_version -ge $_libcurl_wanted ; then
- libcurl_cv_lib_version_ok=yes
- else
- libcurl_cv_lib_version_ok=no
- fi
- ])
- fi
-
- if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then
- if test x"$LIBCURL_CPPFLAGS" = "x" ; then
- LIBCURL_CPPFLAGS=`$_libcurl_config --cflags`
- fi
- if test x"$LIBCURL" = "x" ; then
- LIBCURL=`$_libcurl_config --libs`
-
- # This is so silly, but Apple actually has a bug in their
- # curl-config script. Fixed in Tiger, but there are still
- # lots of Panther installs around.
- case "${host}" in
- powerpc-apple-darwin7*)
- LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'`
- ;;
- esac
- fi
-
- # All curl-config scripts support --feature
- _libcurl_features=`$_libcurl_config --feature`
-
- # Is it modern enough to have --protocols? (7.12.4)
- if test $_libcurl_version -ge 461828 ; then
- _libcurl_protocols=`$_libcurl_config --protocols`
- fi
- else
- _libcurl_try_link=no
- fi
-
- unset _libcurl_wanted
+ AC_CACHE_CHECK([for the version of libcurl],
+ [libcurl_cv_lib_curl_version],
+ [libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $[]2}'`])
+
+ _libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse`
+ _libcurl_wanted=`echo ifelse([$2],,[0],[$2]) | $_libcurl_version_parse`
+
+ if test $_libcurl_wanted -gt 0 ; then
+ AC_CACHE_CHECK([for libcurl >= version $2],
+ [libcurl_cv_lib_version_ok],
+ [
+ if test $_libcurl_version -ge $_libcurl_wanted ; then
+ libcurl_cv_lib_version_ok=yes
+ else
+ libcurl_cv_lib_version_ok=no
+ fi
+ ])
+ fi
+
+ if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then
+ if test x"$LIBCURL_CPPFLAGS" = "x" ; then
+ LIBCURL_CPPFLAGS=`$_libcurl_config --cflags`
+ fi
+ if test x"$LIBCURL" = "x" ; then
+ LIBCURL=`$_libcurl_config --libs`
+
+ # This is so silly, but Apple actually has a bug in their
+ # curl-config script. Fixed in Tiger, but there are still
+ # lots of Panther installs around.
+ case "${host}" in
+ powerpc-apple-darwin7*)
+ LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'`
+ ;;
+ esac
+ fi
+
+ # All curl-config scripts support --feature
+ _libcurl_features=`$_libcurl_config --feature`
+
+ # Is it modern enough to have --protocols? (7.12.4)
+ if test $_libcurl_version -ge 461828 ; then
+ _libcurl_protocols=`$_libcurl_config --protocols`
+ fi
+ else
+ _libcurl_try_link=no
+ fi
+
+ unset _libcurl_wanted
fi
if test $_libcurl_try_link = yes ; then
- # we didn't find curl-config, so let's see if the user-supplied
- # link line (or failing that, "-lcurl") is enough.
- LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"}
+ # we didn't find curl-config, so let's see if the user-supplied
+ # link line (or failing that, "-lcurl") is enough.
+ LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"}
- AC_CACHE_CHECK([whether libcurl is usable],
- [libcurl_cv_lib_curl_usable],
- [
- _libcurl_save_cppflags=$CPPFLAGS
- CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS"
- _libcurl_save_libs=$LIBS
- LIBS="$LIBCURL $LIBS"
+ AC_CACHE_CHECK([whether libcurl is usable],
+ [libcurl_cv_lib_curl_usable],
+ [
+ _libcurl_save_cppflags=$CPPFLAGS
+ CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS"
+ _libcurl_save_libs=$LIBS
+ LIBS="$LIBCURL $LIBS"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <curl/curl.h>]],[[
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <curl/curl.h>]],[[
/* Try and use a few common options to force a failure if we are
missing symbols or can't link. */
int x;
if (x) ;
]])],libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no)
- CPPFLAGS=$_libcurl_save_cppflags
- LIBS=$_libcurl_save_libs
- unset _libcurl_save_cppflags
- unset _libcurl_save_libs
- ])
-
- if test $libcurl_cv_lib_curl_usable = yes ; then
-
- # Does curl_free() exist in this version of libcurl?
- # If not, fake it with free()
-
- _libcurl_save_cppflags=$CPPFLAGS
- CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS"
- _libcurl_save_libs=$LIBS
- LIBS="$LIBS $LIBCURL"
-
- AC_CHECK_FUNC(curl_free,,
- AC_DEFINE(curl_free,free,
- [Define curl_free() as free() if our version of curl lacks curl_free.]))
-
- CPPFLAGS=$_libcurl_save_cppflags
- LIBS=$_libcurl_save_libs
- unset _libcurl_save_cppflags
- unset _libcurl_save_libs
-
- AC_DEFINE(HAVE_LIBCURL,1,
- [Define to 1 if you have a functional curl library.])
- AC_SUBST(LIBCURL_CPPFLAGS)
- AC_SUBST(LIBCURL)
-
- for _libcurl_feature in $_libcurl_features ; do
- AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1])
- eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes
- done
-
- if test "x$_libcurl_protocols" = "x" ; then
-
- # We don't have --protocols, so just assume that all
- # protocols are available
- _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP"
-
- if test x$libcurl_feature_SSL = xyes ; then
- _libcurl_protocols="$_libcurl_protocols HTTPS"
-
- # FTPS wasn't standards-compliant until version
- # 7.11.0 (0x070b00 == 461568)
- if test $_libcurl_version -ge 461568; then
- _libcurl_protocols="$_libcurl_protocols FTPS"
- fi
- fi
-
- # RTSP, IMAP, POP3 and SMTP were added in
- # 7.20.0 (0x071400 == 463872)
- if test $_libcurl_version -ge 463872; then
- _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP"
- fi
- fi
-
- for _libcurl_protocol in $_libcurl_protocols ; do
- AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_protocol_$_libcurl_protocol),[1])
- eval AS_TR_SH(libcurl_protocol_$_libcurl_protocol)=yes
- done
- else
- unset LIBCURL
- unset LIBCURL_CPPFLAGS
- fi
+ CPPFLAGS=$_libcurl_save_cppflags
+ LIBS=$_libcurl_save_libs
+ unset _libcurl_save_cppflags
+ unset _libcurl_save_libs
+ ])
+
+ if test $libcurl_cv_lib_curl_usable = yes ; then
+
+ # Does curl_free() exist in this version of libcurl?
+ # If not, fake it with free()
+
+ _libcurl_save_cppflags=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS"
+ _libcurl_save_libs=$LIBS
+ LIBS="$LIBS $LIBCURL"
+
+ AC_CHECK_FUNC(curl_free,,
+ AC_DEFINE(curl_free,free,
+ [Define curl_free() as free() if our version of curl lacks curl_free.]))
+
+ CPPFLAGS=$_libcurl_save_cppflags
+ LIBS=$_libcurl_save_libs
+ unset _libcurl_save_cppflags
+ unset _libcurl_save_libs
+
+ AC_DEFINE(HAVE_LIBCURL,1,
+ [Define to 1 if you have a functional curl library.])
+ AC_SUBST(LIBCURL_CPPFLAGS)
+ AC_SUBST(LIBCURL)
+
+ for _libcurl_feature in $_libcurl_features ; do
+ AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1])
+ eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes
+ done
+
+ if test "x$_libcurl_protocols" = "x" ; then
+
+ # We don't have --protocols, so just assume that all
+ # protocols are available
+ _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP"
+
+ if test x$libcurl_feature_SSL = xyes ; then
+ _libcurl_protocols="$_libcurl_protocols HTTPS"
+
+ # FTPS wasn't standards-compliant until version
+ # 7.11.0 (0x070b00 == 461568)
+ if test $_libcurl_version -ge 461568; then
+ _libcurl_protocols="$_libcurl_protocols FTPS"
+ fi
+ fi
+
+ # RTSP, IMAP, POP3 and SMTP were added in
+ # 7.20.0 (0x071400 == 463872)
+ if test $_libcurl_version -ge 463872; then
+ _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP"
+ fi
+ fi
+
+ for _libcurl_protocol in $_libcurl_protocols ; do
+ AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_protocol_$_libcurl_protocol),[1])
+ eval AS_TR_SH(libcurl_protocol_$_libcurl_protocol)=yes
+ done
+ else
+ unset LIBCURL
+ unset LIBCURL_CPPFLAGS
+ fi
fi
unset _libcurl_try_link
* @brief Functions and datatypes for the REST (HTTP) transport.
* @file rest.c
*
- * @copyright 2012-2013 Arran Cudbard-Bell <a.cudbard-bell@freeradius.org>
+ * @copyright 2012-2014 Arran Cudbard-Bell <a.cudbard-bell@freeradius.org>
*/
RCSID("$Id$")
-#include <assert.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
* @see http_body_type_t
*/
const http_body_type_t http_body_type_supported[HTTP_BODY_NUM_ENTRIES] = {
- HTTP_BODY_UNSUPPORTED, // HTTP_BODY_UNKOWN
+ HTTP_BODY_UNKNOWN, // HTTP_BODY_UNKOWN
HTTP_BODY_UNSUPPORTED, // HTTP_BODY_UNSUPPORTED
HTTP_BODY_UNSUPPORTED, // HTTP_BODY_UNAVAILABLE
HTTP_BODY_UNSUPPORTED, // HTTP_BODY_INVALID
+ HTTP_BODY_NONE, // HTTP_BODY_NONE
+ HTTP_BODY_CUSTOM, // HTTP_BODY_CUSTOM
HTTP_BODY_POST, // HTTP_BODY_POST
#ifdef HAVE_JSON
HTTP_BODY_JSON, // HTTP_BODY_JSON
* Lib CURL doesn't define symbols for unsupported auth methods
*/
#ifndef CURLOPT_TLSAUTH_SRP
-#define CURLOPT_TLSAUTH_SRP 0
+# define CURLOPT_TLSAUTH_SRP 0
#endif
#ifndef CURLAUTH_BASIC
-#define CURLAUTH_BASIC 0
+# define CURLAUTH_BASIC 0
#endif
#ifndef CURLAUTH_DIGEST
-#define CURLAUTH_DIGEST 0
+# define CURLAUTH_DIGEST 0
#endif
#ifndef CURLAUTH_DIGEST_IE
-#define CURLAUTH_DIGEST_IE 0
+# define CURLAUTH_DIGEST_IE 0
#endif
#ifndef CURLAUTH_GSSNEGOTIATE
-#define CURLAUTH_GSSNEGOTIATE 0
+# define CURLAUTH_GSSNEGOTIATE 0
#endif
#ifndef CURLAUTH_NTLM
-#define CURLAUTH_NTLM 0
+# define CURLAUTH_NTLM 0
#endif
#ifndef CURLAUTH_NTLM_WB
-#define CURLAUTH_NTLM_WB 0
+# define CURLAUTH_NTLM_WB 0
#endif
+#define SET_OPTION(_x, _y)\
+do {\
+ if ((ret = curl_easy_setopt(candle, _x, _y)) != CURLE_OK) {\
+ option = STRINGIFY(_x);\
+ goto error;\
+ }\
+} while (0)
+
const unsigned long http_curl_auth[HTTP_AUTH_NUM_ENTRIES] = {
0, // HTTP_AUTH_UNKNOWN
0, // HTTP_AUTH_NONE
/** Conversion table for method config values.
*
* HTTP verb strings for http_method_t enum values. Used by libcurl in the
- * status line of the outgoing HTTP header, by rest_write_header for decoding
+ * status line of the outgoing HTTP header, by rest_response_header for decoding
* incoming HTTP responses, and by the configuration parser.
*
* @see http_method_t
{ "unsupported", HTTP_BODY_UNSUPPORTED },
{ "unavailable", HTTP_BODY_UNAVAILABLE },
{ "invalid", HTTP_BODY_INVALID },
+ { "none", HTTP_BODY_NONE },
{ "post", HTTP_BODY_POST },
{ "json", HTTP_BODY_JSON },
{ "xml", HTTP_BODY_XML },
/** Conversion table for "Content-Type" header values.
*
- * Used by rest_write_header for parsing incoming headers.
+ * Used by rest_response_header for parsing incoming headers.
*
* Values we expect to see in the 'Content-Type:' header of the incoming
* response.
{ "text/x-yaml", HTTP_BODY_YAML },
{ "application/yaml", HTTP_BODY_YAML },
{ "application/x-yaml", HTTP_BODY_YAML },
+
{ NULL , -1 }
};
+/*
+ * Encoder specific structures.
+ * @todo split encoders/decoders into submodules.
+ */
+typedef struct rest_custom_data {
+ char *p; //!< how much text we've sent so far.
+} rest_custom_data_t;
+
#ifdef HAVE_JSON
/** Flags to control the conversion of JSON values to VALUE_PAIRs.
*
{
CURLcode ret;
+ /* developer sanity */
+ rad_assert((sizeof(http_body_type_supported) / sizeof(*http_body_type_supported)) == HTTP_BODY_NUM_ENTRIES);
+
ret = curl_global_init(CURL_GLOBAL_ALL);
if (ret != CURLE_OK) {
ERROR("rlm_rest (%s): CURL init returned error: %i - %s",
- instance->xlat_name,
- ret, curl_easy_strerror(ret));
+ instance->xlat_name,
+ ret, curl_easy_strerror(ret));
curl_global_cleanup();
return -1;
rlm_rest_curl_context_t *ctx = NULL;
CURL *candle = curl_easy_init();
- CURLcode ret;
+
+ CURLcode ret = CURLE_OK;
+ char const *option = "unknown";
if (!candle) {
ERROR("rlm_rest (%s): Failed to create CURL handle", inst->xlat_name);
return NULL;
}
- if (!*inst->connect_uri) {
+ if (!inst->connect_uri) {
ERROR("rlm_rest (%s): Skipping pre-connect, connect_uri not specified", inst->xlat_name);
return candle;
}
/*
- * Pre-establish TCP connection to webserver. This would usually be
- * done on the first request, but we do it here to minimise
- * latency.
+ * re-establish TCP connection to webserver. This would usually be
+ * done on the first request, but we do it here to minimise
+ * latency.
*/
- ret = curl_easy_setopt(candle, CURLOPT_CONNECT_ONLY, 1);
- if (ret != CURLE_OK) goto error;
-
- ret = curl_easy_setopt(candle, CURLOPT_URL,
- inst->connect_uri);
- if (ret != CURLE_OK) goto error;
+ SET_OPTION(CURLOPT_CONNECT_ONLY, 1);
+ SET_OPTION(CURLOPT_URL, inst->connect_uri);
DEBUG("rlm_rest (%s): Connecting to \"%s\"", inst->xlat_name, inst->connect_uri);
}
/*
- * Allocate memory for the connection handle abstraction.
+ * Allocate memory for the connection handle abstraction.
*/
randle = talloc_zero(inst, rlm_rest_handle_t);
ctx = talloc_zero(randle, rlm_rest_curl_context_t);
ctx->headers = NULL; /* CURL needs this to be NULL */
- ctx->read.instance = inst;
+ ctx->request.instance = inst;
randle->ctx = ctx;
randle->handle = candle;
/*
- * Clear any previously configured options for the first request.
+ * Clear any previously configured options for the first request.
*/
curl_easy_reset(candle);
return randle;
/*
- * Cleanup for error conditions.
+ * Cleanup for error conditions.
*/
- error:
-
- ERROR("rlm_rest (%s): Failed setting curl option: %i - %s", inst->xlat_name, ret, curl_easy_strerror(ret));
+error:
+ ERROR("rlm_rest (%s): Failed setting curl option %s: %s (%i)", inst->xlat_name, option,
+ curl_easy_strerror(ret), ret);
/*
- * So we don't leak CURL handles.
+ * So we don't leak CURL handles.
*/
- connection_error:
-
+connection_error:
curl_easy_cleanup(candle);
if (randle) talloc_free(randle);
*/
int mod_conn_alive(void *instance, void *handle)
{
- rlm_rest_t *inst = instance;
- rlm_rest_handle_t *randle = handle;
- CURL *candle = randle->handle;
+ rlm_rest_t *inst = instance;
+ rlm_rest_handle_t *randle = handle;
+ CURL *candle = randle->handle;
long last_socket;
CURLcode ret;
*/
int mod_conn_delete(UNUSED void *instance, void *handle)
{
- rlm_rest_handle_t *randle = handle;
- CURL *candle = randle->handle;
+ rlm_rest_handle_t *randle = handle;
+ CURL *candle = randle->handle;
curl_easy_cleanup(candle);
return true;
}
+/** Copies a pre-expanded xlat string to the output buffer
+ *
+ * @param[out] out Char buffer to write encoded data to.
+ * @param[in] size Multiply by nmemb to get the length of ptr.
+ * @param[in] nmemb Multiply by size to get the length of ptr.
+ * @param[in] userdata rlm_rest_request_t to keep encoding state between calls.
+ * @return length of data (including NULL) written to ptr, or 0 if no more
+ * data to write.
+ */
+static size_t rest_encode_custom(void *out, size_t size, size_t nmemb, void *userdata)
+{
+ rlm_rest_request_t *ctx = userdata;
+ rest_custom_data_t *data = ctx->encoder;
+
+ size_t freespace = (size * nmemb) - 1;
+ size_t len;
+
+ len = strlcpy(out, data->p, freespace);
+ if (is_truncated(len, freespace)) {
+ data->p += (freespace - 1);
+ return freespace - 1;
+ }
+ data->p += len;
+
+ return len;
+}
+
/** Encodes VALUE_PAIR linked list in POST format
*
* This is a stream function matching the rest_read_t prototype. Multiple
*
* @see rest_decode_post
*
- * @param[out] ptr Char buffer to write encoded data to.
+ * @param[out] out Char buffer to write encoded data to.
* @param[in] size Multiply by nmemb to get the length of ptr.
* @param[in] nmemb Multiply by size to get the length of ptr.
- * @param[in] userdata rlm_rest_read_t to keep encoding state between calls.
+ * @param[in] userdata rlm_rest_request_t to keep encoding state between calls.
* @return length of data (including NULL) written to ptr, or 0 if no more
* data to write.
*/
-static size_t rest_encode_post(void *ptr, size_t size, size_t nmemb,
- void *userdata)
+static size_t rest_encode_post(void *out, size_t size, size_t nmemb, void *userdata)
{
- rlm_rest_read_t *ctx = userdata;
- REQUEST *request = ctx->request; /* Used by RDEBUG */
- VALUE_PAIR *vp;
+ rlm_rest_request_t *ctx = userdata;
+ REQUEST *request = ctx->request; /* Used by RDEBUG */
+ VALUE_PAIR *vp;
- char *p = ptr; /* Position in buffer */
- char *f = ptr; /* Position in buffer of last fully encoded attribute or value */
- char *escaped; /* Pointer to current URL escaped data */
+ char *p = out; /* Position in buffer */
+ char *encoded = p; /* Position in buffer of last fully encoded attribute or value */
+ char *escaped; /* Pointer to current URL escaped data */
- ssize_t len = 0;
- ssize_t s = (size * nmemb) - 1;
+ size_t len = 0;
+ size_t freespace = (size * nmemb) - 1;
/* Allow manual chunking */
- if ((ctx->chunk) && (ctx->chunk <= s)) {
- s = (ctx->chunk - 1);
+ if ((ctx->chunk) && (ctx->chunk <= freespace)) {
+ freespace = (ctx->chunk - 1);
}
if (ctx->state == READ_STATE_END) return 0;
/* Post data requires no headers */
- if (ctx->state == READ_STATE_INIT) {
- ctx->state = READ_STATE_ATTR_BEGIN;
- }
+ if (ctx->state == READ_STATE_INIT) ctx->state = READ_STATE_ATTR_BEGIN;
- while (s > 0) {
- vp = paircurrent(&ctx->cursor);
+ while (freespace > 0) {
+ vp = fr_cursor_current(&ctx->cursor);
if (!vp) {
ctx->state = READ_STATE_END;
- goto end_chunk;
+ break;
}
RDEBUG2("Encoding attribute \"%s\"", vp->da->name);
if (ctx->state == READ_STATE_ATTR_BEGIN) {
escaped = curl_escape(vp->da->name, strlen(vp->da->name));
- len = strlen(escaped);
+ if (!escaped) {
+ REDEBUG("Failed escaping string \"%s\"", vp->da->name);
+ return 0;
+ }
- if (s < (1 + len)) {
+ len = strlen(escaped);
+ if (freespace < (1 + len)) {
curl_free(escaped);
goto no_space;
}
len = sprintf(p, "%s=", escaped);
-
curl_free(escaped);
-
p += len;
- s -= len;
+ freespace -= len;
/*
- * We wrote the attribute header, record progress.
+ * We wrote the attribute header, record progress.
*/
- f = p;
+ encoded = p;
ctx->state = READ_STATE_ATTR_CONT;
}
/*
- * Write out single attribute string.
+ * Write out single attribute string.
*/
- len = vp_prints_value(p , s, vp, 0);
- escaped = curl_escape(p, len);
- len = strlen(escaped);
+ len = vp_prints_value(p, freespace, vp, 0);
+ if (is_truncated(len, freespace)) goto no_space;
+
+ RDEBUG3("\tLength : %zd", len);
+ if (len > 0) {
+ escaped = curl_escape(p, len);
+ if (!escaped) {
+ REDEBUG("Failed escaping string \"%s\"", vp->da->name);
+ return 0;
+ }
+ len = strlen(escaped);
- if (s < len) {
- curl_free(escaped);
- goto no_space;
- }
+ if (freespace < len) {
+ curl_free(escaped);
+ goto no_space;
+ }
- len = strlcpy(p, escaped, len + 1);
+ len = strlcpy(p, escaped, len + 1);
- curl_free(escaped);
+ curl_free(escaped);
- RDEBUG("\tLength : %i", len);
- RDEBUG("\tValue : %s", p);
+ RDEBUG3("\tValue : %s", p);
- p += len;
- s -= len;
+ p += len;
+ freespace -= len;
+ }
- if (!--s) goto no_space;
- *p++ = '&';
+ /*
+ * there are more attributes, insert a separator
+ */
+ if (fr_cursor_next(&ctx->cursor)) {
+ if (freespace < 1) goto no_space;
+ *p++ = '&';
+ freespace--;
+ }
/*
- * We wrote one full attribute value pair, record progress.
+ * We wrote one full attribute value pair, record progress.
*/
- f = p;
- pairnext(&ctx->cursor);
+ encoded = p;
+
ctx->state = READ_STATE_ATTR_BEGIN;
}
- end_chunk:
-
*p = '\0';
- len = p - (char*)ptr;
+ len = p - (char *)out;
- RDEBUG2("POST Data: %s", (char*) ptr);
- RDEBUG2("Returning %i bytes of POST data", len);
+ RDEBUG3("POST Data: %s", (char *)out);
+ RDEBUG3("Returning %zd bytes of POST data", len);
return len;
/*
- * Cleanup for error conditions
+ * Cleanup for error conditions
*/
- no_space:
-
- *f = '\0';
+no_space:
+ *encoded = '\0';
- len = f - (char*)ptr;
+ len = encoded - (char *)out;
- RDEBUG2("POST Data: %s", (char*) ptr);
+ RDEBUG3("POST Data: %s", (char *)out);
/*
- * The buffer wasn't big enough to encode a single attribute chunk.
+ * The buffer wasn't big enough to encode a single attribute chunk.
*/
- if (!len) {
- REDEBUG("AVP exceeds buffer length or chunk");
+ if (len == 0) {
+ REDEBUG("Failed encoding attribute");
} else {
- RDEBUG2("Returning %i bytes of POST data (buffer full or chunk exceeded)", len);
+ RDEBUG3("Returning %zd bytes of POST data (buffer full or chunk exceeded)", len);
}
return len;
}
+#ifdef HAVE_JSON
/** Encodes VALUE_PAIR linked list in JSON format
*
* This is a stream function matching the rest_read_t prototype. Multiple
}
@endverbatim
*
- * @param[out] ptr Char buffer to write encoded data to.
+ * @param[out] out Char buffer to write encoded data to.
* @param[in] size Multiply by nmemb to get the length of ptr.
* @param[in] nmemb Multiply by size to get the length of ptr.
- * @param[in] userdata rlm_rest_read_t to keep encoding state between calls.
+ * @param[in] userdata rlm_rest_request_t to keep encoding state between calls.
* @return length of data (including NULL) written to ptr, or 0 if no more
* data to write.
*/
-static size_t rest_encode_json(void *ptr, size_t size, size_t nmemb,
- void *userdata)
+static size_t rest_encode_json(void *out, size_t size, size_t nmemb, void *userdata)
{
- rlm_rest_read_t *ctx = userdata;
- REQUEST *request = ctx->request; /* Used by RDEBUG */
- VALUE_PAIR *vp, *next;
+ rlm_rest_request_t *ctx = userdata;
+ REQUEST *request = ctx->request; /* Used by RDEBUG */
+ VALUE_PAIR *vp, *next;
- char *p = ptr; /* Position in buffer */
- char *f = ptr; /* Position in buffer of last fully encoded attribute or value */
+ char *p = out; /* Position in buffer */
+ char *encoded = p; /* Position in buffer of last fully encoded attribute or value */
char const *type;
- ssize_t len = 0;
- ssize_t s = (size * nmemb) - 1;
+ size_t len = 0;
+ size_t freespace = (size * nmemb) - 1;
- assert(s > 0);
+ rad_assert(freespace > 0);
/* Allow manual chunking */
- if ((ctx->chunk) && (ctx->chunk <= s)) {
- s = (ctx->chunk - 1);
+ if ((ctx->chunk) && (ctx->chunk <= freespace)) {
+ freespace = (ctx->chunk - 1);
}
if (ctx->state == READ_STATE_END) return 0;
if (ctx->state == READ_STATE_INIT) {
ctx->state = READ_STATE_ATTR_BEGIN;
- if (!--s) goto no_space;
+ if (freespace < 1) goto no_space;
*p++ = '{';
+ freespace--;
}
- while (s > 0) {
- vp = paircurrent(&ctx->cursor);
+ for (;;) {
+ vp = fr_cursor_current(&ctx->cursor);
/*
- * We've encoded all the VPs
+ * We've encoded all the VPs
*/
if (!vp) {
ctx->state = READ_STATE_END;
- if (!--s) goto no_space;
+ if (freespace < 1) goto no_space;
*p++ = '}';
+ freespace--;
- goto end_chunk;
+ break;
}
/*
- * New attribute, write name, type, and beginning of
- * value array.
+ * New attribute, write name, type, and beginning of value array.
*/
RDEBUG2("Encoding attribute \"%s\"", vp->da->name);
if (ctx->state == READ_STATE_ATTR_BEGIN) {
- type = fr_int2str(dict_attr_types, vp->da->type, "¿Unknown?");
+ type = fr_int2str(dict_attr_types, vp->da->type, "<INVALID>");
- len = strlen(type);
- len += strlen(vp->da->name);
-
- if (s < (23 + len)) goto no_space;
-
- len = sprintf(p, "\"%s\":{\"type\":\"%s\",\"value\":[" , vp->da->name, type);
+ len = snprintf(p, freespace + 1, "\"%s\":{\"type\":\"%s\",\"value\":[", vp->da->name, type);
+ if (len >= freespace) goto no_space;
p += len;
- s -= len;
+ freespace -= len;
- RDEBUG2("\tType : %s", type);
+ RDEBUG3("\tType : %s", type);
/*
- * We wrote the attribute header, record progress
- */
- f = p;
+ * We wrote the attribute header, record progress
+ */
+ encoded = p;
ctx->state = READ_STATE_ATTR_CONT;
}
for (;;) {
- len = vp_prints_value_json(p, s, vp);
- if (len >= s) goto no_space;
+ len = vp_prints_value_json(p, freespace, vp);
+ if (is_truncated(len, freespace)) goto no_space;
/*
- * Show actual value length minus quotes
+ * Show actual value length minus quotes
*/
- RDEBUG2("\tLength : %i", (*p == '"') ? (len - 2) : len);
- RDEBUG2("\tValue : %s", p);
+ RDEBUG3("\tLength : %zu", (size_t) (*p == '"') ? (len - 2) : len);
+ RDEBUG3("\tValue : %s", p);
p += len;
- s -= len;
+ freespace -= len;
/*
- * Multivalued attribute, we sorted all the attributes earlier, so multiple
- * instances should occur in a contiguous block.
+ * Multivalued attribute, we sorted all the attributes earlier, so multiple
+ * instances should occur in a contiguous block.
*/
- if ((next = pairnext(&ctx->cursor)) && (vp->da == next->da)) {
+ if ((next = fr_cursor_next(&ctx->cursor)) && (vp->da == next->da)) {
+ if (freespace < 1) goto no_space;
*p++ = ',';
+ freespace--;
/*
- * We wrote one attribute value, record
- * progress.
+ * We wrote one attribute value, record progress.
*/
- f = p;
+ encoded = p;
vp = next;
continue;
}
break;
}
- if (!(s -= 2)) goto no_space;
+ if (freespace < 2) goto no_space;
*p++ = ']';
*p++ = '}';
+ freespace -= 2;
if (next) {
- if (!--s) goto no_space;
+ if (freespace < 1) goto no_space;
*p++ = ',';
+ freespace--;
}
/*
- * We wrote one full attribute value pair, record progress.
+ * We wrote one full attribute value pair, record progress.
*/
- f = p;
+ encoded = p;
ctx->state = READ_STATE_ATTR_BEGIN;
}
- end_chunk:
-
*p = '\0';
- len = p - (char*)ptr;
+ len = p - (char *)out;
- RDEBUG2("JSON Data: %s", (char*) ptr);
- RDEBUG2("Returning %i bytes of JSON data", len);
+ RDEBUG3("JSON Data: %s", (char *)out);
+ RDEBUG3("Returning %zd bytes of JSON data", len);
return len;
/*
- * Were out of buffer space
+ * Were out of buffer space
*/
- no_space:
-
- *f = '\0';
+no_space:
+ *encoded = '\0';
- len = f - (char*)ptr;
+ len = encoded - (char *)out;
- RDEBUG2("JSON Data: %s", (char*) ptr);
+ RDEBUG3("JSON Data: %s", (char *)out);
/*
- * The buffer wasn't big enough to encode a single attribute chunk.
+ * The buffer wasn't big enough to encode a single attribute chunk.
*/
- if (!len) {
+ if (len == 0) {
REDEBUG("AVP exceeds buffer length or chunk");
} else {
- RDEBUG2("Returning %i bytes of JSON data (buffer full or chunk exceeded)", len);
+ RDEBUG2("Returning %zd bytes of JSON data (buffer full or chunk exceeded)", len);
}
return len;
}
+#endif
/** Emulates successive libcurl calls to an encoding function
*
* This function is used when the request will be sent to the HTTP server as one
- * contiguous entity. A buffer of REST_BODY_INCR bytes is allocated and passed
+ * contiguous entity. A buffer of REST_BODY_INIT bytes is allocated and passed
* to the stream encoding function.
*
* If the stream function does not return 0, a new buffer is allocated which is
- * the size of the previous buffer + REST_BODY_INCR bytes, the data from the
+ * the size of the previous buffer + REST_BODY_INIT bytes, the data from the
* previous buffer is copied, and freed, and another call is made to the stream
* function, passing a pointer into the new buffer at the end of the previously
* written data.
* be written.
* @param[in] func Stream function.
* @param[in] limit Maximum buffer size to alloc.
- * @param[in] userdata rlm_rest_read_t to keep encoding state between calls to
+ * @param[in] userdata rlm_rest_request_t to keep encoding state between calls to
* stream function.
* @return the length of the data written to the buffer (excluding NULL) or -1
* if alloc >= limit.
*/
-static ssize_t rest_read_wrapper(char **buffer, rest_read_t func,
- size_t limit, void *userdata)
+static ssize_t rest_request_encode_wrapper(char **buffer, rest_read_t func, size_t limit, void *userdata)
{
char *previous = NULL;
- char *current;
+ char *current = NULL;
- size_t alloc = REST_BODY_INCR; /* Size of buffer to alloc */
- size_t used = 0; /* Size of data written */
- size_t len = 0;
+ size_t alloc = REST_BODY_INIT; /* Size of buffer to alloc */
+ size_t used = 0; /* Size of data written */
+ size_t len = 0;
- while (alloc < limit) {
+ while (alloc <= limit) {
current = rad_malloc(alloc);
if (previous) {
free(previous);
}
- len = func(current + used, REST_BODY_INCR, 1, userdata);
+ len = func(current + used, alloc - used, 1, userdata);
used += len;
if (!len) {
*buffer = current;
return used;
}
- alloc += REST_BODY_INCR;
+ alloc = alloc * 2;
previous = current;
};
return -1;
}
-/** (Re-)Initialises the data in a rlm_rest_read_t.
+/** (Re-)Initialises the data in a rlm_rest_request_t.
*
- * Resets the values of a rlm_rest_read_t to their defaults.
+ * Resets the values of a rlm_rest_request_t to their defaults.
*
* @param[in] request Current request.
* @param[in] ctx to initialise.
* @param[in] sort If true VALUE_PAIRs will be sorted within the VALUE_PAIR
* pointer array.
*/
-static void rest_read_ctx_init(REQUEST *request, rlm_rest_read_t *ctx, bool sort)
+static void rest_request_init(REQUEST *request, rlm_rest_request_t *ctx, bool sort)
{
/*
* Setup stream read data
* Sorts pairs in place, oh well...
*/
if (sort) {
- pairsort(&request->packet->vps, true);
+ pairsort(&request->packet->vps, attrtagcmp);
}
- paircursor(&ctx->cursor, &request->packet->vps);
+ fr_cursor_init(&ctx->cursor, &request->packet->vps);
}
/** Converts POST response into VALUE_PAIRs and adds them to the request
* @param[in] rawlen Length of data in raw buffer.
* @return the number of VALUE_PAIRs processed or -1 on unrecoverable error.
*/
-static int rest_decode_post(UNUSED rlm_rest_t *instance,
- UNUSED rlm_rest_section_t *section,
- REQUEST *request, void *handle, char *raw,
- UNUSED size_t rawlen)
+static int rest_decode_post(UNUSED rlm_rest_t *instance, UNUSED rlm_rest_section_t *section,
+ REQUEST *request, void *handle, char *raw, UNUSED size_t rawlen)
{
- rlm_rest_handle_t *randle = handle;
- CURL *candle = randle->handle;
+ rlm_rest_handle_t *randle = handle;
+ CURL *candle = randle->handle;
char const *p = raw, *q;
DICT_ATTR const *da;
VALUE_PAIR *vp;
- DICT_ATTR const **current, *processed[REST_BODY_MAX_ATTRS + 1];
-
pair_lists_t list_name;
request_refs_t request_name;
REQUEST *reference = request;
VALUE_PAIR **vps;
+ TALLOC_CTX *ctx;
size_t len;
int curl_len; /* Length from last curl_easy_unescape call */
int count = 0;
int ret;
- processed[0] = NULL;
-
/*
- * Empty response?
+ * Empty response?
*/
while (isspace(*p)) p++;
if (*p == '\0') return 0;
- while (((q = strchr(p, '=')) != NULL) &&
- (count < REST_BODY_MAX_ATTRS)) {
- attribute = name;
+ while (((q = strchr(p, '=')) != NULL) && (count < REST_BODY_MAX_ATTRS)) {
reference = request;
name = curl_easy_unescape(candle, p, (q - p), &curl_len);
p = (q + 1);
- RDEBUG("Decoding attribute \"%s\"", name);
+ RDEBUG2("Parsing attribute \"%s\"", name);
+ /*
+ * The attribute pointer is updated to point to the portion of
+ * the string after the list qualifier.
+ */
+ attribute = name;
request_name = radius_request_name(&attribute, REQUEST_CURRENT);
if (request_name == REQUEST_UNKNOWN) {
RWDEBUG("Invalid request qualifier, skipping");
continue;
}
- if (!radius_request(&reference, request_name)) {
- RWDEBUG("Attribute name refers to outer request"
- " but not in a tunnel, skipping");
+ if (radius_request(&reference, request_name) < 0) {
+ RWDEBUG("Attribute name refers to outer request but not in a tunnel, skipping");
curl_free(name);
da = dict_attrbyname(attribute);
if (!da) {
- RWDEBUG("Attribute \"%s\" unknown, skipping",
- attribute);
+ RWDEBUG("Attribute \"%s\" unknown, skipping", attribute);
curl_free(name);
}
vps = radius_list(reference, list_name);
+ rad_assert(vps);
- assert(vps);
+ RDEBUG3("\tType : %s", fr_int2str(dict_attr_types, da->type, "<INVALID>"));
- RDEBUG2("\tType : %s", fr_int2str(dict_attr_types, da->type, "¿Unknown?"));
+ ctx = radius_list_ctx(reference, list_name);
q = strchr(p, '&');
len = (!q) ? (rawlen - (p - raw)) : (unsigned)(q - p);
value = curl_easy_unescape(candle, p, len, &curl_len);
/*
- * If we found a delimiter we want to skip over it,
- * if we didn't we do *NOT* want to skip over the end
- * of the buffer...
+ * If we found a delimiter we want to skip over it,
+ * if we didn't we do *NOT* want to skip over the end
+ * of the buffer...
*/
p += (!q) ? len : (len + 1);
- RDEBUG2("\tLength : %i", curl_len);
- RDEBUG2("\tValue : \"%s\"", value);
+ RDEBUG3("\tLength : %i", curl_len);
+ RDEBUG3("\tValue : \"%s\"", value);
- RDEBUG("Performing xlat expansion of response value");
+ RDEBUG2("Performing xlat expansion of response value");
if (radius_axlat(&expanded, request, value, NULL, NULL) < 0) {
goto skip;
}
- vp = pairalloc(request, da);
+ vp = pairalloc(ctx, da);
if (!vp) {
REDEBUG("Failed creating valuepair");
talloc_free(expanded);
goto error;
}
- vp->op = T_OP_SET;
-
- /*
- * Check to see if we've already processed an
- * attribute of the same type if we have, change the op
- * from T_OP_ADD to T_OP_SET.
- */
- current = processed;
- while (*current++) {
- if (current[0] == da) {
- vp->op = T_OP_ADD;
- break;
- }
- }
-
- if (vp->op != T_OP_ADD) {
- current[0] = da;
- current[1] = NULL;
- }
-
- ret = pairparsevalue(vp, expanded);
- talloc_free(expanded);
- if (!ret) {
+ ret = pairparsevalue(vp, expanded, 0);
+ TALLOC_FREE(expanded);
+ if (ret < 0) {
RWDEBUG("Incompatible value assignment, skipping");
talloc_free(vp);
goto skip;
}
- if (++count == REST_BODY_MAX_ATTRS) {
- REDEBUG("At maximum attribute limit");
- return count;
- }
+ pairadd(vps, vp);
- skip:
+ count++;
+ skip:
curl_free(name);
curl_free(value);
continue;
- error:
-
+ error:
curl_free(name);
curl_free(value);
* @param[in] leaf object containing the VALUE_PAIR value.
* @return The VALUE_PAIR just created, or NULL on error.
*/
-static VALUE_PAIR *json_pairmake_leaf(UNUSED rlm_rest_t *instance,
- UNUSED rlm_rest_section_t *section,
+static VALUE_PAIR *json_pairmake_leaf(UNUSED rlm_rest_t *instance, UNUSED rlm_rest_section_t *section,
REQUEST *request, DICT_ATTR const *da,
json_flags_t *flags, json_object *leaf)
{
*/
value = json_object_get_string(leaf);
- RDEBUG2("\tType : %s", fr_int2str(dict_attr_types, da->type,
- "¿Unknown?"));
- RDEBUG2("\tLength : %i", strlen(value));
- RDEBUG2("\tValue : \"%s\"", value);
+ RDEBUG3("\tType : %s", fr_int2str(dict_attr_types, da->type, "<INVALID>"));
+ RDEBUG3("\tLength : %zu", strlen(value));
+ RDEBUG3("\tValue : \"%s\"", value);
if (flags->do_xlat) {
if (radius_axlat(&expanded, request, value, NULL, NULL) < 0) {
to_parse = value;
}
- vp = paircreate(NULL, da->attr, da->vendor);
+ vp = paircreate(request, da->attr, da->vendor);
if (!vp) {
- REDEBUG("Failed creating valuepair");
+ RWDEBUG("Failed creating valuepair, skipping...");
talloc_free(expanded);
return NULL;
vp->op = flags->op;
- ret = pairparsevalue(vp, to_parse);
+ ret = pairparsevalue(vp, to_parse, 0);
talloc_free(expanded);
- if (!ret) {
- RDEBUG("Incompatible value assignment, skipping");
+ if (ret < 0) {
+ RWDEBUG("Incompatible value assignment, skipping...");
talloc_free(vp);
return NULL;
* @param[in] request Current request.
* @param[in] object containing root node, or parent node.
* @param[in] level Current nesting level.
- * @param[in] max_attrs counter, decremented after each VALUE_PAIR is created,
+ * @param[in] max counter, decremented after each VALUE_PAIR is created,
* when 0 no more attributes will be processed.
- * @return VALUE_PAIR or NULL on error.
+ * @return number of attributes created or < 0 on error.
*/
-static VALUE_PAIR *json_pairmake(rlm_rest_t *instance,
- UNUSED rlm_rest_section_t *section,
- REQUEST *request, json_object *object,
- UNUSED int level, int *max_attrs)
+static int json_pairmake(rlm_rest_t *instance, UNUSED rlm_rest_section_t *section,
+ REQUEST *request, json_object *object, UNUSED int level, int max)
{
- char const *p;
- char *q;
-
- char const *name, *attribute;
-
- struct json_object *value, *idx, *tmp;
struct lh_entry *entry;
- json_flags_t flags;
-
- DICT_ATTR const *da;
- VALUE_PAIR *vp = NULL;
-
- request_refs_t request_name;
- pair_lists_t list_name;
- REQUEST *reference = request;
- VALUE_PAIR **vps;
-
- int i, len;
+ int max_attrs = max;
if (!json_object_is_type(object, json_type_object)) {
- RDEBUG("Can't process VP container, expected JSON object, got \"%s\", skipping",
- json_type_to_name(json_object_get_type(object)));
- return NULL;
- }
+ REDEBUG("Can't process VP container, expected JSON object"
+#ifdef HAVE_JSON_TYPE_TO_NAME
+ "got \"%s\", skipping...",
+ json_type_to_name(json_object_get_type(object)));
+#else
+ ", skipping...");
+#endif
+ return -1;
+ }
/*
* Process VP container
*/
- entry = json_object_get_object(object)->head;
- while (entry) {
- flags.op = T_OP_SET;
- flags.do_xlat = 1;
- flags.is_json = 0;
+ for (entry = json_object_get_object(object)->head;
+ entry;
+ entry = entry->next) {
+ int i = 0, elements;
+ struct json_object *value, *element, *tmp;
- name = (char*)entry->k;
+ char const *name = (char const *)entry->k;
- /* Fix the compiler warnings regarding const... */
- memcpy(&value, &entry->v, sizeof(value));
+ json_flags_t flags = {
+ .op = T_OP_SET,
+ .do_xlat = 1,
+ .is_json = 0
+ };
- entry = entry->next;
+ value_pair_tmpl_t dst;
+ REQUEST *current = request;
+ VALUE_PAIR **vps, *vp = NULL;
- /*
- * For people handcrafting JSON responses
- */
- p = name;
- while ((p = q = strchr(p, '|'))) {
- *q = ':';
- p++;
- }
+ memset(&dst, 0, sizeof(dst));
- attribute = name;
- reference = request;
+ /* Fix the compiler warnings regarding const... */
+ memcpy(&value, &entry->v, sizeof(value));
/*
- * Resolve attribute name to a dictionary entry and
- * pairlist.
+ * Resolve attribute name to a dictionary entry and pairlist.
*/
- RDEBUG2("Decoding attribute \"%s\"", name);
-
- request_name = radius_request_name(&attribute, REQUEST_CURRENT);
- if (request_name == REQUEST_UNKNOWN) {
- RWDEBUG("Request qualifier unknown, skipping");
-
- continue;
- }
-
- if (!radius_request(&reference, request_name)) {
- RWDEBUG("Attribute name refers to outer request"
- " but not in a tunnel, skipping");
+ RDEBUG2("Parsing attribute \"%s\"", name);
+ if (radius_parse_attr(&dst, name, REQUEST_CURRENT, PAIR_LIST_REPLY) < 0) {
+ RWDEBUG("Failed parsing attribute: %s, skipping...", fr_strerror());
continue;
}
- list_name = radius_list_name(&attribute, PAIR_LIST_REPLY);
- if (list_name == PAIR_LIST_UNKNOWN) {
- RWDEBUG("Invalid list qualifier, skipping");
-
+ if (radius_request(¤t, dst.vpt_request) < 0) {
+ RWDEBUG("Attribute name refers to outer request but not in a tunnel, skipping...");
continue;
}
- da = dict_attrbyname(attribute);
- if (!da) {
- RWDEBUG("Attribute \"%s\" unknown, skipping",
- attribute);
-
+ vps = radius_list(current, dst.vpt_list);
+ if (!vps) {
+ RWDEBUG("List not valid in this context, skipping...");
continue;
}
- vps = radius_list(reference, list_name);
-
- assert(vps);
-
/*
- * Alternate JSON structure that allows operator,
- * and other flags to be specified.
+ * Alternative JSON structure which allows operator,
+ * and other flags to be specified.
*
* "<name>":{
* "do_xlat":<bool>,
*/
if (json_object_is_type(value, json_type_object)) {
/*
- * Process operator if present.
+ * Process operator if present.
*/
tmp = json_object_object_get(value, "op");
if (tmp) {
flags.op = fr_str2int(fr_tokens, json_object_get_string(tmp), 0);
if (!flags.op) {
- RDEBUG("Invalid operator value \"%s\","
- " skipping", tmp);
+ RWDEBUG("Invalid operator value \"%s\", skipping...",
+ json_object_get_string(tmp));
continue;
}
}
/*
- * Process optional do_xlat bool.
+ * Process optional do_xlat bool.
*/
tmp = json_object_object_get(value, "do_xlat");
if (tmp) {
}
/*
- * Process optional is_json bool.
+ * Process optional is_json bool.
*/
tmp = json_object_object_get(value, "is_json");
if (tmp) {
}
/*
- * Value key must be present if were using
- * the expanded syntax.
+ * Value key must be present if were using the expanded syntax.
*/
value = json_object_object_get(value, "value");
if (!value) {
- RDEBUG("Value key missing, skipping", value);
+ RWDEBUG("Value key missing, skipping...");
continue;
}
- }
+ }
/*
- * Setup pairmake / recursion loop.
+ * Setup pairmake / recursion loop.
*/
- if (!flags.is_json &&
- json_object_is_type(value, json_type_array)) {
- len = json_object_array_length(value);
- if (!len) {
- RDEBUG("Zero length value array, skipping",
- value);
+ if (!flags.is_json && json_object_is_type(value, json_type_array)) {
+ elements = json_object_array_length(value);
+ if (!elements) {
+ RWDEBUG("Zero length value array, skipping...");
continue;
}
- idx = json_object_array_get_idx(value, 0);
+ element = json_object_array_get_idx(value, 0);
} else {
- len = 1;
- idx = value;
+ elements = 1;
+ element = value;
}
- i = 0;
+ /*
+ * A JSON 'value' key, may have multiple elements, iterate
+ * over each of them, creating a new VALUE_PAIR.
+ */
do {
- if (!(*max_attrs)--) {
- REDEBUG("At maximum attribute limit");
- return NULL;
+ if (max_attrs-- <= 0) {
+ RWDEBUG("At maximum attribute limit");
+ return max;
}
/*
- * Automagically switch the op for multivalued
- * attributes.
+ * Automagically switch the op for multivalued attributes.
*/
- if (((flags.op == T_OP_SET) ||
- (flags.op == T_OP_EQ)) && (len > 1)) {
+ if (((flags.op == T_OP_SET) || (flags.op == T_OP_EQ)) && (i >= 1)) {
flags.op = T_OP_ADD;
}
- if (!flags.is_json && json_object_is_type(value, json_type_object)) {
+ if (json_object_is_type(element, json_type_object) && !flags.is_json) {
/* TODO: Insert nested VP into VP structure...*/
- REDEBUG("Found nested VP, these are not yet supported");
+ RWDEBUG("Found nested VP, these are not yet supported, skipping...");
- return NULL;
+ continue;
/*
vp = json_pairmake(instance, section,
request, value,
level + 1, max_attrs);*/
} else {
- vp = json_pairmake_leaf(instance, section,
- request, da, &flags,
- idx);
+ vp = json_pairmake_leaf(instance, section, request, dst.vpt_da, &flags, element);
+ if (!vp) continue;
}
- } while ((++i < len) &&
- (idx = json_object_array_get_idx(value, i)));
- }
+ debug_pair(vp);
+ radius_pairmove(current, vps, vp, false);
+ /*
+ * If we call json_object_array_get_idx on something that's not an array
+ * the behaviour appears to be to occasionally segfault.
+ */
+ } while ((++i < elements) && (element = json_object_array_get_idx(value, i)));
+ }
- return vp;
+ return max - max_attrs;
}
/** Converts JSON response into VALUE_PAIRs and adds them to the request.
* @param[in] rawlen Length of data in raw buffer.
* @return the number of VALUE_PAIRs processed or -1 on unrecoverable error.
*/
-static int rest_decode_json(rlm_rest_t *instance,
- UNUSED rlm_rest_section_t *section,
- REQUEST *request, UNUSED void *handle,
- char *raw, UNUSED size_t rawlen)
+static int rest_decode_json(rlm_rest_t *instance, UNUSED rlm_rest_section_t *section,
+ REQUEST *request, UNUSED void *handle, char *raw, UNUSED size_t rawlen)
{
char const *p = raw;
struct json_object *json;
- int max = REST_BODY_MAX_ATTRS;
+ int ret;
/*
- * Empty response?
+ * Empty response?
*/
while (isspace(*p)) p++;
if (*p == '\0') return 0;
json = json_tokener_parse(p);
if (!json) {
- RDEBUG("Malformed JSON data \"%s\"", raw);
+ REDEBUG("Malformed JSON data \"%s\"", raw);
return -1;
}
- json_pairmake(instance, section, request, json, 0, &max);
+ ret = json_pairmake(instance, section, request, json, 0, REST_BODY_MAX_ATTRS);
/*
- * Decrement reference count for root object, should free entire
- * JSON tree.
+ * Decrement reference count for root object, should free entire JSON tree.
*/
json_object_put(json);
- return (REST_BODY_MAX_ATTRS - max);
+ return ret;
}
#endif
* Matches prototype for CURLOPT_HEADERFUNCTION, and will be called directly
* by libcurl.
*
- * @param[in] ptr Char buffer where inbound header data is written.
+ * @param[in] in Char buffer where inbound header data is written.
* @param[in] size Multiply by nmemb to get the length of ptr.
* @param[in] nmemb Multiply by size to get the length of ptr.
- * @param[in] userdata rlm_rest_write_t to keep parsing state between calls.
+ * @param[in] userdata rlm_rest_response_t to keep parsing state between calls.
* @return Length of data processed, or 0 on error.
*/
-static size_t rest_write_header(void *ptr, size_t size, size_t nmemb,
- void *userdata)
+static size_t rest_response_header(void *in, size_t size, size_t nmemb, void *userdata)
{
- rlm_rest_write_t *ctx = userdata;
- REQUEST *request = ctx->request; /* Used by RDEBUG */
+ rlm_rest_response_t *ctx = userdata;
+ REQUEST *request = ctx->request; /* Used by RDEBUG */
- char const *p = ptr, *q;
- char *tmp;
+ char const *p = in, *q;
size_t const t = (size * nmemb);
size_t s = t;
size_t len;
http_body_type_t type;
- http_body_type_t supp;
+
+ /*
+ * Curl seems to throw these (\r\n) in before the next set of headers when
+ * looks like it's just a body separator and safe to ignore after we
+ * receive a 100 Continue.
+ */
+ if (t == 2 && ((p[0] == '\r') && (p[1] == '\n'))) return t;
switch (ctx->state) {
case WRITE_STATE_INIT:
- RDEBUG("Processing header");
+ RDEBUG2("Processing response header");
/*
- * HTTP/<version> <reason_code>[ <reason_phrase>]\r\n
+ * HTTP/<version> <reason_code>[ <reason_phrase>]\r\n
*
- * "HTTP/1.1 " (8) + "100 " (4) + "\r\n" (2) = 14
+ * "HTTP/1.1 " (8) + "100 " (4) + "\r\n" (2) = 14
*/
- if (s < 14) goto malformed;
-
+ if (s < 14) {
+ REDEBUG("Malformed HTTP header: Status line too short");
+ goto malformed;
+ }
/*
- * Check start of header matches...
+ * Check start of header matches...
*/
- if (strncasecmp("HTTP/", p, 5) != 0) goto malformed;
-
+ if (strncasecmp("HTTP/", p, 5) != 0) {
+ REDEBUG("Malformed HTTP header: Missing HTTP version");
+ goto malformed;
+ }
p += 5;
s -= 5;
/*
- * Skip the version field, next space should mark start
- * of reason_code.
+ * Skip the version field, next space should mark start of reason_code.
*/
q = memchr(p, ' ', s);
- if (!q) goto malformed;
+ if (!q) {
+ RDEBUG("Malformed HTTP header: Missing reason code");
+ goto malformed;
+ }
s -= (q - p);
p = q;
/*
- * Process reason_code.
+ * Process reason_code.
*
- * " 100" (4) + "\r\n" (2) = 6
+ * " 100" (4) + "\r\n" (2) = 6
*/
- if (s < 6) goto malformed;
+ if (s < 6) {
+ REDEBUG("Malformed HTTP header: Reason code too short");
+ goto malformed;
+ }
p++;
s--;
- /* Char after reason code must be a space, or \r */
+ /* Char after reason code must be a space, or \r */
if (!((p[3] == ' ') || (p[3] == '\r'))) goto malformed;
ctx->code = atoi(p);
/*
- * Process reason_phrase (if present).
+ * Process reason_phrase (if present).
*/
if (p[3] == ' ') {
p += 4;
len = (q - p);
- tmp = rad_malloc(len + 1);
- strlcpy(tmp, p, len + 1);
-
- RDEBUG("\tStatus : %i (%s)", ctx->code, tmp);
-
- free(tmp);
+ RDEBUG2("\tStatus : %i (%.*s)", ctx->code, (int) len, p);
} else {
- RDEBUG("\tStatus : %i", ctx->code);
+ RDEBUG2("\tStatus : %i", ctx->code);
}
ctx->state = WRITE_STATE_PARSE_HEADERS;
s -= 14;
/*
- * Check to see if there's a parameter
- * separator.
+ * Check to see if there's a parameter separator.
*/
q = memchr(p, ';', s);
/*
- * If there's not, find the end of this
- * header.
+ * If there's not, find the end of this header.
*/
if (!q) q = memchr(p, '\r', s);
- len = (!q) ? s : (unsigned)(q - p);
+ len = !q ? s : (size_t) (q - p);
+ type = fr_substr2int(http_content_type_table, p, HTTP_BODY_UNKNOWN, len);
- type = fr_substr2int(http_content_type_table,
- p, HTTP_BODY_UNKNOWN,
- len);
- supp = http_body_type_supported[type];
+ RDEBUG2("\tType : %s (%.*s)", fr_int2str(http_body_type_table, type, "<INVALID>"),
+ (int) len, p);
- tmp = rad_malloc(len + 1);
- strlcpy(tmp, p, len + 1);
-
- RDEBUG("\tType : %s (%s)",
- fr_int2str(http_body_type_table, type,
- "¿Unknown?"), tmp);
-
- free(tmp);
-
- if (type == HTTP_BODY_UNKNOWN) {
- RDEBUG("Couldn't determine type, using"
- " request type \"%s\".",
- fr_int2str(http_body_type_table,
- ctx->type,
- "¿Unknown?"));
+ /*
+ * Figure out if the type is supported by one of the decoders.
+ */
+ if (ctx->force_to != HTTP_BODY_UNKNOWN) {
+ if (ctx->force_to != ctx->type) {
+ RDEBUG3("Forcing body type to \"%s\"",
+ fr_int2str(http_body_type_table, ctx->force_to, "<INVALID>"));
+ ctx->type = ctx->force_to;
+ }
+ /*
+ * Assume the force_to value has already been validation.
+ */
+ } else switch (http_body_type_supported[ctx->type]) {
+ case HTTP_BODY_UNKNOWN:
+ RWDEBUG("Couldn't determine type, using the request's type \"%s\".",
+ fr_int2str(http_body_type_table, ctx->type, "<INVALID>"));
+ break;
- } else if (supp == HTTP_BODY_UNSUPPORTED) {
- RDEBUG("Type \"%s\" is currently"
- " unsupported",
- fr_int2str(http_body_type_table,
- type, "¿Unknown?"));
- ctx->type = HTTP_BODY_UNSUPPORTED;
- } else if (supp == HTTP_BODY_UNAVAILABLE) {
- RDEBUG("Type \"%s\" is currently"
- " unavailable, please rebuild"
- " this module with the required"
- " headers",
- fr_int2str(http_body_type_table,
- type, "¿Unknown?"));
+ case HTTP_BODY_UNSUPPORTED:
+ REDEBUG("Type \"%s\" is currently unsupported",
+ fr_int2str(http_body_type_table, ctx->type, "<INVALID>"));
ctx->type = HTTP_BODY_UNSUPPORTED;
+ break;
- } else if (supp == HTTP_BODY_INVALID) {
- RDEBUG("Type \"%s\" is not a valid web"
- " API data markup format",
- fr_int2str(http_body_type_table,
- type, "¿Unknown?"));
+ case HTTP_BODY_UNAVAILABLE:
+ REDEBUG("Type \"%s\" is unavailable, please rebuild this module with the required "
+ "library", fr_int2str(http_body_type_table, ctx->type, "<INVALID>"));
+ ctx->type = HTTP_BODY_UNAVAILABLE;
+ break;
+ case HTTP_BODY_INVALID:
+ REDEBUG("Type \"%s\" is not a valid web API data markup format",
+ fr_int2str(http_body_type_table, ctx->type, "<INVALID>"));
ctx->type = HTTP_BODY_INVALID;
+ break;
- } else if (type != ctx->type) {
+ /* supported type */
+ default:
ctx->type = type;
+ break;
}
}
break;
default:
break;
}
+
+ /*
+ * If we got a 100 Continue, we need to send additional payload data.
+ * reset the state to WRITE_STATE_INIT, so that when were called again
+ * we overwrite previous header data with that from the proper header.
+ */
+ if (ctx->code == 100) {
+ RDEBUG2("Continuing...");
+ ctx->state = WRITE_STATE_INIT;
+ }
+
return t;
- malformed:
+malformed:
+ {
+ char escaped[1024];
+
+ fr_print_string((char *) in, t, escaped, sizeof(escaped));
- RDEBUG("Incoming header was malformed");
- ctx->code = -1;
+ REDEBUG("Received %zu bytes of response data: %s", t, escaped);
+ ctx->code = -1;
+ }
return (t - s);
}
* @param[in] ptr Char buffer where inbound header data is written
* @param[in] size Multiply by nmemb to get the length of ptr.
* @param[in] nmemb Multiply by size to get the length of ptr.
- * @param[in] userdata rlm_rest_write_t to keep parsing state between calls.
+ * @param[in] userdata rlm_rest_response_t to keep parsing state between calls.
* @return length of data processed, or 0 on error.
*/
-static size_t rest_write_body(void *ptr, size_t size, size_t nmemb,
- void *userdata)
+static size_t rest_response_body(void *ptr, size_t size, size_t nmemb, void *userdata)
{
- rlm_rest_write_t *ctx = userdata;
- REQUEST *request = ctx->request; /* Used by RDEBUG */
+ rlm_rest_response_t *ctx = userdata;
+ REQUEST *request = ctx->request; /* Used by RDEBUG */
- char const *p = ptr;
+ char const *p = ptr, *q;
char *tmp;
size_t const t = (size * nmemb);
+ if (t == 0) return 0;
+
/*
- * Any post processing of headers should go here...
+ * Any post processing of headers should go here...
*/
if (ctx->state == WRITE_STATE_PARSE_HEADERS) {
ctx->state = WRITE_STATE_PARSE_CONTENT;
switch (ctx->type) {
case HTTP_BODY_UNSUPPORTED:
- return t;
-
+ case HTTP_BODY_UNAVAILABLE:
case HTTP_BODY_INVALID:
- tmp = rad_malloc(t + 1);
- strlcpy(tmp, p, t + 1);
+ while ((q = memchr(p, '\n', t - (p - (char *)ptr)))) {
+ REDEBUG("%.*s", (int) (q - p), p);
+ p = q + 1;
+ }
+
+ if (*p != '\0') {
+ REDEBUG("%.*s", (int)(t - (p - (char *)ptr)), p);
+ }
+
+ return t;
- RDEBUG2("%s", tmp);
+ case HTTP_BODY_NONE:
+ while ((q = memchr(p, '\n', t - (p - (char *)ptr)))) {
+ RDEBUG3("%.*s", (int) (q - p), p);
+ p = q + 1;
+ }
- free(tmp);
+ if (*p != '\0') {
+ RDEBUG3("%.*s", (int)(t - (p - (char *)ptr)), p);
+ }
return t;
default:
if (t > (ctx->alloc - ctx->used)) {
- ctx->alloc += ((t + 1) > REST_BODY_INCR) ?
- t + 1 : REST_BODY_INCR;
+ ctx->alloc += ((t + 1) > REST_BODY_INIT) ? t + 1 : REST_BODY_INIT;
tmp = ctx->buffer;
/* If data has been written previously */
if (tmp) {
- strlcpy(ctx->buffer, tmp,
- (ctx->used + 1));
+ strlcpy(ctx->buffer, tmp, (ctx->used + 1));
free(tmp);
}
}
return t;
}
-/** (Re-)Initialises the data in a rlm_rest_write_t.
+/** (Re-)Initialises the data in a rlm_rest_response_t.
*
- * This resets the values of the a rlm_rest_write_t to their defaults.
+ * This resets the values of the a rlm_rest_response_t to their defaults.
* Must be called between encoding sessions.
*
- * @see rest_write_body
- * @see rest_write_header
+ * @see rest_response_body
+ * @see rest_response_header
*
* @param[in] request Current request.
* @param[in] ctx data to initialise.
* @param[in] type Default http_body_type to use when decoding raw data, may be
- * overwritten by rest_write_header.
+ * overwritten by rest_response_header.
*/
-static void rest_write_ctx_init(REQUEST *request, rlm_rest_write_t *ctx,
- http_body_type_t type)
+static void rest_response_init(REQUEST *request, rlm_rest_response_t *ctx, http_body_type_t type)
{
- ctx->request = request;
- ctx->type = type;
- ctx->state = WRITE_STATE_INIT;
- ctx->alloc = 0;
- ctx->used = 0;
- ctx->buffer = NULL;
+ ctx->request = request;
+ ctx->type = type;
+ ctx->state = WRITE_STATE_INIT;
+ ctx->alloc = 0;
+ ctx->used = 0;
+ ctx->buffer = NULL;
}
-/** Frees the intermediary buffer created by rest_write.
+/** Extracts pointer to buffer containing response data
*
- * @param[in] ctx data to be freed.
+ * @param[out] out Where to write the pointer to the buffer.
+ * @param[in] handle used for the last request.
+ * @return > 0 if data is available.
*/
-static void rest_write_free(rlm_rest_write_t *ctx)
+size_t rest_get_handle_data(char const **out, rlm_rest_handle_t *handle)
{
- if (ctx->buffer != NULL) {
- free(ctx->buffer);
- }
+ rlm_rest_curl_context_t *ctx = handle->ctx;
+
+ rad_assert(ctx->response.buffer || (!ctx->response.buffer && !ctx->response.used));
+
+ *out = ctx->response.buffer;
+ return ctx->response.used;
}
/** Configures body specific curlopts.
* transfers (NULL if not using chunked mode).
* @return 0 on success -1 on error.
*/
-static int rest_request_config_body(UNUSED rlm_rest_t *instance,
- rlm_rest_section_t *section,
- REQUEST *request,
- rlm_rest_handle_t *handle,
- rest_read_t func)
+static int rest_request_config_body(UNUSED rlm_rest_t *instance, rlm_rest_section_t *section,
+ REQUEST *request, rlm_rest_handle_t *handle, rest_read_t func)
{
rlm_rest_curl_context_t *ctx = handle->ctx;
- CURL *candle = handle->handle;
+ CURL *candle = handle->handle;
+
+ CURLcode ret = CURLE_OK;
+ char const *option = "unknown";
ssize_t len;
- CURLcode ret;
- if (section->chunk > 0) {
- ret = curl_easy_setopt(candle, CURLOPT_READDATA, &ctx->read);
- if (ret != CURLE_OK) goto error;
+ /*
+ * We were provided with no read function, assume this means
+ * no body should be sent.
+ */
+ if (!func) {
+ SET_OPTION(CURLOPT_POSTFIELDSIZE, 0);
+ return 0;
+ }
- ret = curl_easy_setopt(candle, CURLOPT_READFUNCTION, rest_encode_json);
- if (ret != CURLE_OK) goto error;
- } else {
- len = rest_read_wrapper(&ctx->body, func, REST_BODY_MAX_LEN,
- &ctx->read);
- if (len <= 0) {
- REDEBUG("Failed creating HTTP body content");
- }
+ /*
+ * Chunked transfer encoding means the body will be sent in
+ * multiple parts.
+ */
+ if (section->chunk > 0) {
+ SET_OPTION(CURLOPT_READDATA, &ctx->request);
+ SET_OPTION(CURLOPT_READFUNCTION, func);
- ret = curl_easy_setopt(candle, CURLOPT_POSTFIELDS, ctx->body);
- if (ret != CURLE_OK) goto error;
+ return 0;
+ }
- ret = curl_easy_setopt(candle, CURLOPT_POSTFIELDSIZE, len);
- if (ret != CURLE_OK) goto error;
+ /*
+ * If were not doing chunked encoding then we read the entire
+ * body into a buffer, and send it in one go.
+ */
+ len = rest_request_encode_wrapper(&ctx->body, func, REST_BODY_MAX_LEN, &ctx->request);
+ if (len <= 0) {
+ REDEBUG("Failed creating HTTP body content");
+ return -1;
}
+ SET_OPTION(CURLOPT_POSTFIELDS, ctx->body);
+ SET_OPTION(CURLOPT_POSTFIELDSIZE, len);
+
return 0;
- error:
- REDEBUG("Failed setting curl option: %i - %s", ret, curl_easy_strerror(ret));
+error:
+ REDEBUG("Failed setting curl option %s: %s (%i)", option, curl_easy_strerror(ret), ret);
return -1;
}
http_body_type_t type,
char const *uri, char const *username, char const *password)
{
- rlm_rest_handle_t *randle = handle;
- rlm_rest_curl_context_t *ctx = randle->ctx;
- CURL *candle = randle->handle;
+ rlm_rest_handle_t *randle = handle;
+ rlm_rest_curl_context_t *ctx = randle->ctx;
+ CURL *candle = randle->handle;
http_auth_type_t auth = section->auth;
- CURLcode ret;
+ CURLcode ret = CURLE_OK;
+ char const *option = "unknown";
+ char const *content_type;
long val = 1;
char buffer[512];
/*
* Setup any header options and generic headers.
*/
- ret = curl_easy_setopt(candle, CURLOPT_URL, uri);
- if (ret != CURLE_OK) goto error;
+ SET_OPTION(CURLOPT_URL, uri);
+ SET_OPTION(CURLOPT_USERAGENT, "FreeRADIUS " RADIUSD_VERSION_STRING);
- ret = curl_easy_setopt(candle, CURLOPT_USERAGENT, "FreeRADIUS");
- if (ret != CURLE_OK) goto error;
-
- snprintf(buffer, (sizeof(buffer) - 1), "Content-Type: %s",
- fr_int2str(http_content_type_table, type, "¿Unknown?"));
+ content_type = fr_int2str(http_content_type_table, type, section->body_str);
+ snprintf(buffer, sizeof(buffer), "Content-Type: %s", content_type);
ctx->headers = curl_slist_append(ctx->headers, buffer);
if (!ctx->headers) goto error_header;
if (section->timeout) {
- ret = curl_easy_setopt(candle, CURLOPT_TIMEOUT,
- section->timeout);
- if (ret != CURLE_OK) goto error;
+ SET_OPTION(CURLOPT_TIMEOUT, section->timeout);
}
- ret = curl_easy_setopt(candle, CURLOPT_PROTOCOLS,
- (CURLPROTO_HTTP | CURLPROTO_HTTPS));
- if (ret != CURLE_OK) goto error;
+ SET_OPTION(CURLOPT_PROTOCOLS, (CURLPROTO_HTTP | CURLPROTO_HTTPS));
/*
* FreeRADIUS custom headers
*/
- snprintf(buffer, (sizeof(buffer) - 1), "X-FreeRADIUS-Section: %s",
- section->name);
+ RDEBUG3("Adding custom headers:");
+ snprintf(buffer, sizeof(buffer), "X-FreeRADIUS-Section: %s", section->name);
+ RDEBUG3("\t%s", buffer);
ctx->headers = curl_slist_append(ctx->headers, buffer);
if (!ctx->headers) goto error_header;
- snprintf(buffer, (sizeof(buffer) - 1), "X-FreeRADIUS-Server: %s",
- request->server);
+ snprintf(buffer, sizeof(buffer), "X-FreeRADIUS-Server: %s", request->server);
+ RDEBUG3("\t%s", buffer);
ctx->headers = curl_slist_append(ctx->headers, buffer);
if (!ctx->headers) goto error_header;
*/
switch (method) {
case HTTP_METHOD_GET :
- ret = curl_easy_setopt(candle, CURLOPT_HTTPGET,
- val);
- if (ret != CURLE_OK) goto error;
-
+ SET_OPTION(CURLOPT_HTTPGET, val);
break;
case HTTP_METHOD_POST :
- ret = curl_easy_setopt(candle, CURLOPT_POST,
- val);
- if (ret != CURLE_OK) goto error;
-
+ SET_OPTION(CURLOPT_POST, val);
break;
case HTTP_METHOD_PUT :
- ret = curl_easy_setopt(candle, CURLOPT_PUT,
- val);
- if (ret != CURLE_OK) goto error;
-
+ SET_OPTION(CURLOPT_PUT, val);
break;
case HTTP_METHOD_DELETE :
- ret = curl_easy_setopt(candle, CURLOPT_HTTPGET,
- val);
- if (ret != CURLE_OK) goto error;
-
- ret = curl_easy_setopt(candle,
- CURLOPT_CUSTOMREQUEST, "DELETE");
- if (ret != CURLE_OK) goto error;
-
+ SET_OPTION(CURLOPT_HTTPGET, val);
+ SET_OPTION(CURLOPT_CUSTOMREQUEST, "DELETE");
break;
case HTTP_METHOD_CUSTOM :
- ret = curl_easy_setopt(candle, CURLOPT_HTTPGET,
- val);
- if (ret != CURLE_OK) goto error;
-
- ret = curl_easy_setopt(candle,
- CURLOPT_CUSTOMREQUEST,
- section->method);
- if (ret != CURLE_OK) goto error;
+ SET_OPTION(CURLOPT_HTTPGET, val);
+ SET_OPTION(CURLOPT_CUSTOMREQUEST, section->method_str);
break;
default:
- assert(0);
+ rad_assert(0);
break;
};
*/
if (auth) {
if ((auth >= HTTP_AUTH_BASIC) &&
- (auth <= HTTP_AUTH_ANY_SAFE)) {
- ret = curl_easy_setopt(candle, CURLOPT_HTTPAUTH, http_curl_auth[auth]);
- if (ret != CURLE_OK) goto error;
+ (auth <= HTTP_AUTH_ANY_SAFE)) {
+ SET_OPTION(CURLOPT_HTTPAUTH, http_curl_auth[auth]);
if (username) {
- ret = curl_easy_setopt(candle, CURLOPT_USERNAME, username);
- if (ret != CURLE_OK) {
- goto error;
- }
+ SET_OPTION(CURLOPT_USERNAME, username);
} else if (section->username) {
if (radius_xlat(buffer, sizeof(buffer), request, section->username, NULL, NULL) < 0) {
+ option = STRINGIFY(CURLOPT_USERNAME);
goto error;
}
- ret = curl_easy_setopt(candle, CURLOPT_USERNAME, buffer);
- if (ret != CURLE_OK) {
- goto error;
- }
+ SET_OPTION(CURLOPT_USERNAME, buffer);
}
if (password) {
- ret = curl_easy_setopt(candle, CURLOPT_PASSWORD, password);
- if (ret != CURLE_OK) {
- goto error;
- }
+ SET_OPTION(CURLOPT_PASSWORD, password);
} else if (section->password) {
if (radius_xlat(buffer, sizeof(buffer), request, section->password, NULL, NULL) < 0) {
+ option = STRINGIFY(CURLOPT_PASSWORD);
goto error;
}
- ret = curl_easy_setopt(candle, CURLOPT_PASSWORD, buffer);
- if (ret != CURLE_OK) {
- goto error;
- }
+ SET_OPTION(CURLOPT_PASSWORD, buffer);
}
#ifdef CURLOPT_TLSAUTH_USERNAME
} else if (type == HTTP_AUTH_TLS_SRP) {
- ret = curl_easy_setopt(candle, CURLOPT_TLSAUTH_TYPE, http_curl_auth[auth]);
+ SET_OPTION(CURLOPT_TLSAUTH_TYPE, http_curl_auth[auth]);
if (username) {
- ret = curl_easy_setopt(candle, CURLOPT_TLSAUTH_USERNAME, username);
- if (ret != CURLE_OK) {
- goto error;
- }
+ SET_OPTION(CURLOPT_TLSAUTH_USERNAME, username);
} else if (section->username) {
if (radius_xlat(buffer, sizeof(buffer), request, section->username, NULL, NULL) < 0) {
+ option = STRINGIFY(CURLOPT_TLSAUTH_USERNAME);
goto error;
}
- ret = curl_easy_setopt(candle, CURLOPT_TLSAUTH_USERNAME, buffer);
- if (ret != CURLE_OK) {
- goto error;
- }
+ SET_OPTION(CURLOPT_TLSAUTH_USERNAME, buffer);
}
if (password) {
- ret = curl_easy_setopt(candle, CURLOPT_TLSAUTH_PASSWORD, password);
- if (ret != CURLE_OK) {
- goto error;
- }
+ SET_OPTION(CURLOPT_TLSAUTH_PASSWORD, password);
} else if (section->password) {
if (radius_xlat(buffer, sizeof(buffer), request, section->password, NULL, NULL) < 0) {
+ option = STRINGIFY(CURLOPT_TLSAUTH_PASSWORD);
goto error;
}
- ret = curl_easy_setopt(candle, CURLOPT_TLSAUTH_PASSWORD, buffer);
- if (ret != CURLE_OK) {
- goto error;
- }
+ SET_OPTION(CURLOPT_TLSAUTH_PASSWORD, buffer);
}
#endif
}
* Set SSL/TLS authentication parameters
*/
if (section->tls_certificate_file) {
- ret = curl_easy_setopt(candle,
- CURLOPT_SSLCERT,
- section->tls_certificate_file);
- if (ret != CURLE_OK) goto error;
+ SET_OPTION(CURLOPT_SSLCERT, section->tls_certificate_file);
}
if (section->tls_private_key_file) {
- ret = curl_easy_setopt(candle,
- CURLOPT_SSLKEY,
- section->tls_private_key_file);
- if (ret != CURLE_OK) goto error;
+ SET_OPTION(CURLOPT_SSLKEY, section->tls_private_key_file);
}
if (section->tls_private_key_password) {
- ret = curl_easy_setopt(candle,
- CURLOPT_KEYPASSWD,
- section->tls_private_key_password);
- if (ret != CURLE_OK) goto error;
+ SET_OPTION(CURLOPT_KEYPASSWD, section->tls_private_key_password);
}
if (section->tls_ca_file) {
- ret = curl_easy_setopt(candle,
- CURLOPT_ISSUERCERT,
- section->tls_ca_file);
- if (ret != CURLE_OK) goto error;
+ SET_OPTION(CURLOPT_ISSUERCERT, section->tls_ca_file);
}
if (section->tls_ca_path) {
- ret = curl_easy_setopt(candle,
- CURLOPT_CAPATH,
- section->tls_ca_path);
- if (ret != CURLE_OK) goto error;
+ SET_OPTION(CURLOPT_CAPATH, section->tls_ca_path);
}
if (section->tls_random_file) {
- ret = curl_easy_setopt(candle,
- CURLOPT_RANDOM_FILE,
- section->tls_random_file);
- if (ret != CURLE_OK) goto error;
+ SET_OPTION(CURLOPT_RANDOM_FILE, section->tls_random_file);
}
if (section->tls_check_cert) {
- ret = curl_easy_setopt(candle,
- CURLOPT_SSL_VERIFYHOST,
- (section->tls_check_cert_cn == true) ?
- 2 : 0);
- if (ret != CURLE_OK) goto error;
+ SET_OPTION(CURLOPT_SSL_VERIFYHOST, (section->tls_check_cert_cn == true) ? 2 : 0);
} else {
- ret = curl_easy_setopt(candle,
- CURLOPT_SSL_VERIFYPEER,
- 0);
- if (ret != CURLE_OK) goto error;
+ SET_OPTION(CURLOPT_SSL_VERIFYPEER, 0);
}
/*
- * Tell CURL how to get HTTP body content, and how to process
- * incoming data.
+ * Tell CURL how to get HTTP body content, and how to process incoming data.
*/
- rest_write_ctx_init(request, &ctx->write, type);
+ rest_response_init(request, &ctx->response, type);
- ret = curl_easy_setopt(candle, CURLOPT_HEADERFUNCTION,
- rest_write_header);
- if (ret != CURLE_OK) goto error;
+ SET_OPTION(CURLOPT_HEADERFUNCTION, rest_response_header);
+ SET_OPTION(CURLOPT_HEADERDATA, &ctx->response);
+ SET_OPTION(CURLOPT_WRITEFUNCTION, rest_response_body);
+ SET_OPTION(CURLOPT_WRITEDATA, &ctx->response);
- ret = curl_easy_setopt(candle, CURLOPT_HEADERDATA,
- &ctx->write);
- if (ret != CURLE_OK) goto error;
-
- ret = curl_easy_setopt(candle, CURLOPT_WRITEFUNCTION,
- rest_write_body);
- if (ret != CURLE_OK) goto error;
-
- ret = curl_easy_setopt(candle, CURLOPT_WRITEDATA,
- &ctx->write);
- if (ret != CURLE_OK) goto error;
+ /*
+ * Force parsing the body text as a particular encoding.
+ */
+ ctx->response.force_to = section->force_to;
switch (method) {
case HTTP_METHOD_GET :
case HTTP_METHOD_DELETE :
- return 0;
+ RDEBUG3("Using a HTTP method which does not require a body. Forcing request body type to \"none\"");
+ goto finish;
case HTTP_METHOD_POST :
case HTTP_METHOD_PUT :
case HTTP_METHOD_CUSTOM :
if (section->chunk > 0) {
- ctx->read.chunk = section->chunk;
+ ctx->request.chunk = section->chunk;
- ctx->headers = curl_slist_append(ctx->headers,
- "Expect:");
+ ctx->headers = curl_slist_append(ctx->headers, "Expect:");
if (!ctx->headers) goto error_header;
- ctx->headers = curl_slist_append(ctx->headers,
- "Transfer-Encoding: chunked");
+ ctx->headers = curl_slist_append(ctx->headers, "Transfer-Encoding: chunked");
if (!ctx->headers) goto error_header;
}
- switch (type) {
-#ifdef HAVE_JSON
- case HTTP_BODY_JSON:
- rest_read_ctx_init(request, &ctx->read, 1);
+ RDEBUG3("Request body content-type will be \"%s\"",
+ fr_int2str(http_content_type_table, type, section->body_str));
+ break;
- if (rest_request_config_body(instance, section, request, handle,
- rest_encode_json) < 0) {
- return -1;
- }
+ default:
+ rad_assert(0);
+ };
- break;
-#endif
+ /*
+ * Setup encoder specific options
+ */
+ switch (type) {
+ case HTTP_BODY_NONE:
+ if (rest_request_config_body(instance, section, request, handle,
+ NULL) < 0) {
+ return -1;
+ }
- case HTTP_BODY_POST:
- rest_read_ctx_init(request, &ctx->read, 0);
+ break;
- if (rest_request_config_body(instance, section, request, handle,
- rest_encode_post) < 0) {
- return -1;
- }
+ case HTTP_BODY_CUSTOM:
+ {
+ rest_custom_data_t *data;
+ char *expanded = NULL;
- break;
+ if (radius_axlat(&expanded, request, section->data, NULL, NULL) < 0) {
+ return -1;
+ }
+
+ data = talloc_zero(request, rest_custom_data_t);
+ data->p = expanded;
+
+ /* Use the encoder specific pointer to store the data we need to encode */
+ ctx->request.encoder = data;
+ if (rest_request_config_body(instance, section, request, handle,
+ rest_encode_custom) < 0) {
+ TALLOC_FREE(ctx->request.encoder);
+ return -1;
+ }
+
+ break;
+ }
- default:
- assert(0);
+#ifdef HAVE_JSON
+ case HTTP_BODY_JSON:
+ rest_request_init(request, &ctx->request, true);
+
+ if (rest_request_config_body(instance, section, request, handle,
+ rest_encode_json) < 0) {
+ return -1;
}
- ret = curl_easy_setopt(candle, CURLOPT_HTTPHEADER,
- ctx->headers);
- if (ret != CURLE_OK) goto error;
+ break;
+#endif
+
+ case HTTP_BODY_POST:
+ rest_request_init(request, &ctx->request, false);
+
+ if (rest_request_config_body(instance, section, request, handle,
+ rest_encode_post) < 0) {
+ return -1;
+ }
break;
default:
- assert(0);
- };
+ rad_assert(0);
+ }
+
+
+finish:
+ SET_OPTION(CURLOPT_HTTPHEADER, ctx->headers);
return 0;
- error:
- RDEBUG("Failed setting curl option: %i - %s", ret, curl_easy_strerror(ret));
+error:
+ REDEBUG("Failed setting curl option %s: %s (%i)", option, curl_easy_strerror(ret), ret);
return -1;
- error_header:
- RDEBUG("Failed creating header", instance->xlat_name);
+error_header:
+ REDEBUG("Failed creating header");
return -1;
}
* @param[in] handle to use.
* @return 0 on success or -1 on error.
*/
-int rest_request_perform(UNUSED rlm_rest_t *instance,
- UNUSED rlm_rest_section_t *section,
+int rest_request_perform(UNUSED rlm_rest_t *instance, UNUSED rlm_rest_section_t *section,
REQUEST *request, void *handle)
{
- rlm_rest_handle_t *randle = handle;
- CURL *candle = randle->handle;
- CURLcode ret;
+ rlm_rest_handle_t *randle = handle;
+ CURL *candle = randle->handle;
+ CURLcode ret;
ret = curl_easy_perform(candle);
if (ret != CURLE_OK) {
/** Sends the response to the correct decode function.
*
- * Uses the Content-Type information written in rest_write_header to
+ * Uses the Content-Type information written in rest_response_header to
* determine the correct decode function to use. The decode function will
* then convert the raw received data into VALUE_PAIRs.
*
* @param[in] handle to use.
* @return 0 on success or -1 on error.
*/
-int rest_request_decode(rlm_rest_t *instance,
- UNUSED rlm_rest_section_t *section,
- REQUEST *request, void *handle)
+int rest_response_decode(rlm_rest_t *instance, UNUSED rlm_rest_section_t *section,
+ REQUEST *request, void *handle)
{
- rlm_rest_handle_t *randle = handle;
- rlm_rest_curl_context_t *ctx = randle->ctx;
+ rlm_rest_handle_t *randle = handle;
+ rlm_rest_curl_context_t *ctx = randle->ctx;
int ret = -1; /* -Wsometimes-uninitialized */
- if (!ctx->write.buffer) {
- RDEBUG("Skipping attribute processing, no body data received");
+ if (!ctx->response.buffer) {
+ RDEBUG2("Skipping attribute processing, no valid body data received");
return ret;
}
- RDEBUG("Processing body");
+ RDEBUG3("Processing response body");
+
+ switch (ctx->response.type) {
+ case HTTP_BODY_NONE:
+ return 0;
- switch (ctx->write.type) {
case HTTP_BODY_POST:
- ret = rest_decode_post(instance, section, request,
- handle, ctx->write.buffer,
- ctx->write.used);
+ ret = rest_decode_post(instance, section, request, handle, ctx->response.buffer, ctx->response.used);
break;
+
#ifdef HAVE_JSON
case HTTP_BODY_JSON:
- ret = rest_decode_json(instance, section, request,
- handle, ctx->write.buffer,
- ctx->write.used);
+ ret = rest_decode_json(instance, section, request, handle, ctx->response.buffer, ctx->response.used);
break;
#endif
+
case HTTP_BODY_UNSUPPORTED:
case HTTP_BODY_UNAVAILABLE:
case HTTP_BODY_INVALID:
return -1;
default:
- assert(0);
+ rad_assert(0);
}
return ret;
* Resets all options associated with a CURL handle, and frees any headers
* associated with it.
*
- * Calls rest_read_ctx_free and rest_write_free to free any memory used by
+ * Calls rest_read_ctx_free and rest_response_free to free any memory used by
* context data.
*
* @param[in] instance configuration data.
* @param[in] section configuration data.
* @param[in] handle to cleanup.
*/
-void rest_request_cleanup(UNUSED rlm_rest_t *instance,
- UNUSED rlm_rest_section_t *section, void *handle)
+void rest_request_cleanup(UNUSED rlm_rest_t *instance, UNUSED rlm_rest_section_t *section, void *handle)
{
- rlm_rest_handle_t *randle = handle;
- rlm_rest_curl_context_t *ctx = randle->ctx;
- CURL *candle = randle->handle;
+ rlm_rest_handle_t *randle = handle;
+ rlm_rest_curl_context_t *ctx = randle->ctx;
+ CURL *candle = randle->handle;
/*
- * Clear any previously configured options
- */
- curl_easy_reset(candle);
+ * Clear any previously configured options
+ */
+ curl_easy_reset(candle);
+
+ /*
+ * Free header list
+ */
+ if (ctx->headers != NULL) {
+ curl_slist_free_all(ctx->headers);
+ ctx->headers = NULL;
+ }
/*
- * Free header list
- */
- if (ctx->headers != NULL) {
- curl_slist_free_all(ctx->headers);
- ctx->headers = NULL;
- }
+ * Free body data (only used if chunking is disabled)
+ */
+ if (ctx->body != NULL) {
+ free(ctx->body);
+ ctx->body = NULL;
+ }
/*
- * Free body data (only used if chunking is disabled)
- */
- if (ctx->body != NULL) free(ctx->body);
-
- /*
- * Free other context info
- */
- rest_write_free(&ctx->write);
+ * Free response data
+ */
+ if (ctx->response.buffer) {
+ free(ctx->response.buffer);
+ ctx->response.buffer = NULL;
+ }
+
+ TALLOC_FREE(ctx->request.encoder);
+ TALLOC_FREE(ctx->response.decoder);
}
/** URL encodes a string.
* @param[in] arg pointer, gives context for escaping.
* @return length of data written to out (excluding NULL).
*/
-static size_t rest_uri_escape(UNUSED REQUEST *request, char *out, size_t outlen,
- char const *raw, UNUSED void *arg)
+size_t rest_uri_escape(UNUSED REQUEST *request, char *out, size_t outlen, char const *raw, UNUSED void *arg)
{
char *escaped;
*
* @param[out] out Where to write the pointer to the new buffer containing the escaped URI.
* @param[in] instance configuration data.
- * @param[in] section configuration data.
+ * @param[in] uri configuration data.
* @param[in] request Current request
* @return length of data written to buffer (excluding NULL) or < 0 if an error
* occurred.
*/
-ssize_t rest_uri_build(char **out, UNUSED rlm_rest_t *instance, rlm_rest_section_t *section, REQUEST *request)
+ssize_t rest_uri_build(char **out, UNUSED rlm_rest_t *instance, REQUEST *request, char const *uri)
{
- char const *p;
- char *path_exp = NULL;
+ char const *p;
+ char *path_exp = NULL;
- char *scheme;
- char const *path;
+ char *scheme;
+ char const *path;
- ssize_t len, outlen;
+ ssize_t len;
- p = section->uri;
+ p = uri;
/*
- * All URLs must contain at least <scheme>://<server>/
+ * All URLs must contain at least <scheme>://<server>/
*/
p = strchr(p, ':');
if (!p || (*++p != '/') || (*++p != '/')) {
goto malformed;
}
- len = (p - section->uri);
+ len = (p - uri);
/*
- * Allocate a temporary buffer to hold the first part of the URI
+ * Allocate a temporary buffer to hold the first part of the URI
*/
scheme = talloc_array(request, char, len + 1);
- strlcpy(scheme, section->uri, len + 1);
+ strlcpy(scheme, uri, len + 1);
- path = (section->uri + len);
+ path = (uri + len);
len = radius_axlat(out, request, scheme, NULL, NULL);
talloc_free(scheme);
return 0;
}
- outlen = len;
-
len = radius_axlat(&path_exp, request, path, rest_uri_escape, NULL);
if (len < 0) {
TALLOC_FREE(*out);
return 0;
}
- *out = talloc_strdup_append(*out, path_exp);
+ MEM(*out = talloc_strdup_append(*out, path_exp));
talloc_free(path_exp);
- return outlen += len;
+ return talloc_array_length(*out) - 1; /* array_length includes \0 */
+}
+
+/** Unescapes the host portion of a URI string
+ *
+ * This is required because the xlat functions which operate on the input string
+ * cannot distinguish between host and path components.
+ *
+ * @param[out] out Where to write the pointer to the new buffer containing the escaped URI.
+ * @param[in] instance configuration data.
+ * @param[in] request Current request
+ * @param[in] handle to use.
+ * @param[in] uri configuration data.
+ * @return length of data written to buffer (excluding NULL) or < 0 if an error
+ * occurred.
+ */
+ssize_t rest_uri_host_unescape(char **out, UNUSED rlm_rest_t *instance, REQUEST *request,
+ void *handle, char const *uri)
+{
+ rlm_rest_handle_t *randle = handle;
+ CURL *candle = randle->handle;
+
+ char const *p;
+
+ char *scheme;
+
+ ssize_t len;
+
+ p = uri;
+
+ /*
+ * All URLs must contain at least <scheme>://<server>/
+ */
+ p = strchr(p, ':');
+ if (!p || (*++p != '/') || (*++p != '/')) {
+ malformed:
+ REDEBUG("Error URI is malformed, can't find start of path");
+ return -1;
+ }
+ p = strchr(p + 1, '/');
+ if (!p) {
+ goto malformed;
+ }
+
+ len = (p - uri);
+
+ /*
+ * Unescape any special sequences in the first part of the URI
+ */
+ scheme = curl_easy_unescape(candle, uri, len, NULL);
+ if (!scheme) {
+ REDEBUG("Error unescaping host");
+ return -1;
+ }
+
+ MEM(*out = talloc_typed_asprintf(request, "%s%s", scheme, p));
+ curl_free(scheme);
+
+ return talloc_array_length(*out) - 1; /* array_length includes \0 */
}
* @brief Function prototypes and datatypes for the REST (HTTP) transport.
* @file rest.h
*
- * @copyright 2012-2013 Arran Cudbard-Bell <a.cudbard-bell@freeradius.org>
+ * @copyright 2012-2014 Arran Cudbard-Bell <a.cudbard-bell@freeradius.org>
*/
RCSIDH(other_h, "$Id$")
#define REST_URI_MAX_LEN 2048
#define REST_BODY_MAX_LEN 8192
-#define REST_BODY_INCR 512
+#define REST_BODY_INIT 1024
#define REST_BODY_MAX_ATTRS 256
typedef enum {
HTTP_BODY_UNSUPPORTED,
HTTP_BODY_UNAVAILABLE,
HTTP_BODY_INVALID,
+ HTTP_BODY_NONE,
+ HTTP_BODY_CUSTOM,
HTTP_BODY_POST,
HTTP_BODY_JSON,
HTTP_BODY_XML,
extern const FR_NAME_NUMBER http_body_type_table[];
-extern const FR_NAME_NUMBER http_content_header_table[];
+extern const FR_NAME_NUMBER http_content_type_table[];
/*
* Structure for section configuration
*/
typedef struct rlm_rest_section_t {
- char const *name;
- char *uri;
-
- char *method_str;
- http_method_t method;
-
- char *body_str;
- http_body_type_t body;
-
- char *username;
- char *password;
- char *auth_str;
- http_auth_type_t auth;
- bool require_auth;
-
- char *tls_certificate_file;
- char *tls_private_key_file;
- char *tls_private_key_password;
- char *tls_ca_file;
- char *tls_ca_path;
- char *tls_random_file;
- bool tls_check_cert;
- bool tls_check_cert_cn;
-
- int timeout;
- unsigned int chunk;
+ char const *name; //!< Section name.
+ char const *uri; //!< URI to send HTTP request to.
+
+ char const *method_str; //!< The string version of the HTTP method.
+ http_method_t method; //!< What HTTP method should be used, GET, POST etc...
+
+ char const *body_str; //!< The string version of the encoding/content type.
+ http_body_type_t body; //!< What encoding type should be used.
+
+ http_body_type_t force_to; //!< Override the Content-Type header in the response
+ //!< to force decoding as a particular type.
+
+ char const *data; //!< Custom body data (optional).
+
+ char const *auth_str; //!< The string version of the Auth-Type.
+ http_auth_type_t auth; //!< HTTP auth type.
+ bool require_auth; //!< Whether HTTP-Auth is required or not.
+ char const *username; //!< Username used for HTTP-Auth
+ char const *password; //!< Password used for HTTP-Auth
+
+ char const *tls_certificate_file;
+ char const *tls_private_key_file;
+ char const *tls_private_key_password;
+ char const *tls_ca_file;
+ char const *tls_ca_path;
+ char const *tls_random_file;
+ bool tls_check_cert;
+ bool tls_check_cert_cn;
+
+ uint32_t timeout; //!< Timeout passed to CURL.
+ uint32_t chunk; //!< Max chunk-size (mainly for testing the encoders)
} rlm_rest_section_t;
/*
* Structure for module configuration
*/
typedef struct rlm_rest_t {
- char const *xlat_name;
+ char const *xlat_name; //!< Instance name.
- char *connect_uri;
+ char const *connect_uri; //!< URI we attempt to connect to, to pre-establish
+ //!< TCP connections.
- fr_connection_pool_t *conn_pool;
+ fr_connection_pool_t *conn_pool; //!< Pointer to the connection pool.
- rlm_rest_section_t authorize;
- rlm_rest_section_t authenticate;
- rlm_rest_section_t accounting;
- rlm_rest_section_t checksimul;
- rlm_rest_section_t postauth;
+ rlm_rest_section_t authorize; //!< Configuration specific to authorisation.
+ rlm_rest_section_t authenticate; //!< Configuration specific to authentication.
+ rlm_rest_section_t accounting; //!< Configuration specific to accounting.
+ rlm_rest_section_t checksimul; //!< Configuration specific to simultaneous session
+ //!< checking.
+ rlm_rest_section_t post_auth; //!< Configuration specific to Post-auth
} rlm_rest_t;
/*
/*
* Outbound data context (passed to CURLOPT_READFUNCTION as CURLOPT_READDATA)
*/
-typedef struct rlm_rest_read_t {
- rlm_rest_t *instance;
- REQUEST *request;
- read_state_t state;
+typedef struct rlm_rest_request_t {
+ rlm_rest_t *instance; //!< This instance of rlm_rest.
+ REQUEST *request; //!< Current request.
+ read_state_t state; //!< Encoder state
+
+ vp_cursor_t cursor; //!< Cursor pointing to the start of the list to encode.
- vp_cursor_t cursor;
+ size_t chunk; //!< Chunk size
- unsigned int chunk;
-} rlm_rest_read_t;
+ void *encoder; //!< Encoder specific data.
+} rlm_rest_request_t;
/*
* Curl inbound data context (passed to CURLOPT_WRITEFUNCTION and
* CURLOPT_HEADERFUNCTION as CURLOPT_WRITEDATA and CURLOPT_HEADERDATA)
*/
-typedef struct rlm_rest_write_t {
- rlm_rest_t *instance;
- REQUEST *request;
- write_state_t state;
+typedef struct rlm_rest_response_t {
+ rlm_rest_t *instance; //!< This instance of rlm_rest.
+ REQUEST *request; //!< Current request.
+ write_state_t state; //!< Decoder state.
+
+ char *buffer; //!< Raw incoming HTTP data.
+ size_t alloc; //!< Space allocated for buffer.
+ size_t used; //!< Space used in buffer.
- char *buffer; /* HTTP incoming raw data */
- size_t alloc; /* Space allocated for buffer */
- size_t used; /* Space used in buffer */
+ int code; //!< HTTP Status Code.
+ http_body_type_t type; //!< HTTP Content Type.
+ http_body_type_t force_to; //!< Force decoding the body type as a particular encoding.
- int code; /* HTTP Status Code */
- http_body_type_t type; /* HTTP Content Type */
-} rlm_rest_write_t;
+ void *decoder; //!< Decoder specific data.
+} rlm_rest_response_t;
/*
* Curl context data
*/
typedef struct rlm_rest_curl_context_t {
- struct curl_slist *headers;
- char *body;
- rlm_rest_read_t read;
- rlm_rest_write_t write;
+ struct curl_slist *headers; //!< Any HTTP headers which will be sent with the
+ //!< request.
+
+ char *body; //!< Pointer to the buffer which contains body data/
+ //!< Only used when not performing chunked encoding.
+
+ rlm_rest_request_t request; //!< Request context data.
+ rlm_rest_response_t response; //!< Response context data.
} rlm_rest_curl_context_t;
/*
* Connection API handle
*/
typedef struct rlm_rest_handle_t {
- void *handle; /* Real Handle */
- void *ctx; /* Context */
+ void *handle; //!< Real Handle.
+ rlm_rest_curl_context_t *ctx; //!< Context.
} rlm_rest_handle_t;
/*
rlm_rest_section_t *section, REQUEST *request,
void *handle, http_method_t method,
http_body_type_t type, char const *uri,
- char const *username, char const *password);
+ char const *username, char const *password) CC_HINT(nonnull (1,2,3,4,7));
int rest_request_perform(rlm_rest_t *instance,
rlm_rest_section_t *section, REQUEST *request,
void *handle);
-int rest_request_decode(rlm_rest_t *instance,
+int rest_response_decode(rlm_rest_t *instance,
UNUSED rlm_rest_section_t *section, REQUEST *request,
void *handle);
void rest_request_cleanup(rlm_rest_t *instance, rlm_rest_section_t *section,
void *handle);
-#define rest_get_handle_code(handle)(((rlm_rest_curl_context_t*)((rlm_rest_handle_t*)handle)->ctx)->write.code)
+#define rest_get_handle_code(handle)(((rlm_rest_curl_context_t*)((rlm_rest_handle_t*)handle)->ctx)->response.code)
+
+#define rest_get_handle_type(handle)(((rlm_rest_curl_context_t*)((rlm_rest_handle_t*)handle)->ctx)->response.type)
-#define rest_get_handle_type(handle)(((rlm_rest_curl_context_t*)((rlm_rest_handle_t*)handle)->ctx)->write.type)
+size_t rest_get_handle_data(char const **out, rlm_rest_handle_t *handle);
/*
* Helper functions
*/
-ssize_t rest_uri_build(char **out, rlm_rest_t *instance, rlm_rest_section_t *section, REQUEST *request);
+size_t rest_uri_escape(UNUSED REQUEST *request, char *out, size_t outlen, char const *raw, UNUSED void *arg);
+ssize_t rest_uri_build(char **out, rlm_rest_t *instance, REQUEST *request, char const *uri);
+ssize_t rest_uri_host_unescape(char **out, UNUSED rlm_rest_t *instance, REQUEST *request,
+ void *handle, char const *uri);
* @file rlm_rest.c
* @brief Integrate FreeRADIUS with RESTfull APIs
*
- * @copyright 2012-2013 Arran Cudbard-Bell <arran.cudbardb@freeradius.org>
+ * @copyright 2012-2014 Arran Cudbard-Bell <arran.cudbardb@freeradius.org>
*/
RCSID("$Id$")
#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/modules.h>
#include <freeradius-devel/token.h>
+#include <freeradius-devel/rad_assert.h>
#include "rest.h"
* TLS Configuration
*/
static CONF_PARSER tls_config[] = {
- { "ca_file", PW_TYPE_FILE_INPUT,
- offsetof(rlm_rest_section_t,tls_ca_file), NULL, NULL},
- { "ca_path", PW_TYPE_FILE_INPUT,
- offsetof(rlm_rest_section_t,tls_ca_path), NULL, NULL},
- { "certificate_file", PW_TYPE_FILE_INPUT,
- offsetof(rlm_rest_section_t,tls_certificate_file), NULL, NULL},
- { "private_key_file", PW_TYPE_FILE_INPUT,
- offsetof(rlm_rest_section_t,tls_private_key_file), NULL, NULL },
- { "private_key_password", PW_TYPE_STRING_PTR,
- offsetof(rlm_rest_section_t, tls_private_key_password), NULL, NULL },
- { "random_file", PW_TYPE_STRING_PTR, /* OK if it changes on HUP */
- offsetof(rlm_rest_section_t,tls_random_file), NULL, NULL },
- { "check_cert", PW_TYPE_BOOLEAN,
- offsetof(rlm_rest_section_t, tls_check_cert), NULL, "yes" },
- { "check_cert_cn", PW_TYPE_BOOLEAN,
- offsetof(rlm_rest_section_t, tls_check_cert_cn), NULL, "yes" },
+ { "ca_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_rest_section_t, tls_ca_file), NULL },
+ { "ca_path", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_rest_section_t, tls_ca_path), NULL },
+ { "certificate_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_rest_section_t, tls_certificate_file), NULL },
+ { "private_key_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_rest_section_t, tls_private_key_file), NULL },
+ { "private_key_password", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, rlm_rest_section_t, tls_private_key_password), NULL },
+ { "random_file", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_rest_section_t, tls_random_file), NULL },
+ { "check_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_rest_section_t, tls_check_cert), "yes" },
+ { "check_cert_cn", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_rest_section_t, tls_check_cert_cn), "yes" },
{ NULL, -1, 0, NULL, NULL }
};
* buffer over-flows.
*/
static const CONF_PARSER section_config[] = {
- { "uri", PW_TYPE_STRING_PTR,
- offsetof(rlm_rest_section_t, uri), NULL, "" },
- { "method", PW_TYPE_STRING_PTR,
- offsetof(rlm_rest_section_t, method_str), NULL, "GET" },
- { "body", PW_TYPE_STRING_PTR,
- offsetof(rlm_rest_section_t, body_str), NULL, "post" },
+ { "uri", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_rest_section_t, uri), "" },
+ { "method", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_rest_section_t, method_str), "GET" },
+ { "body", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_rest_section_t, body_str), "none" },
+ { "data", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_rest_section_t, data), NULL },
/* User authentication */
- { "auth", PW_TYPE_STRING_PTR,
- offsetof(rlm_rest_section_t, auth_str), NULL, "none" },
- { "username", PW_TYPE_STRING_PTR,
- offsetof(rlm_rest_section_t, username), NULL, NULL },
- { "password", PW_TYPE_STRING_PTR,
- offsetof(rlm_rest_section_t, password), NULL, NULL },
- { "require_auth", PW_TYPE_BOOLEAN,
- offsetof(rlm_rest_section_t, require_auth), NULL, "no"},
+ { "auth", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_rest_section_t, auth_str), "none" },
+ { "username", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_rest_section_t, username), NULL },
+ { "password", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_rest_section_t, password), NULL },
+ { "require_auth", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_rest_section_t, require_auth), "no" },
/* Transfer configuration */
- { "timeout", PW_TYPE_INTEGER,
- offsetof(rlm_rest_section_t, timeout), NULL, "0" },
- { "chunk", PW_TYPE_INTEGER,
- offsetof(rlm_rest_section_t, chunk), NULL, "0" },
+ { "timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_rest_section_t, timeout), "4" },
+ { "chunk", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_rest_section_t, chunk), "0" },
/* TLS Parameters */
- { "tls", PW_TYPE_SUBSECTION, 0, NULL, (void const *) tls_config },
+ { "tls", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) tls_config },
{ NULL, -1, 0, NULL, NULL }
};
static const CONF_PARSER module_config[] = {
- { "connect_uri", PW_TYPE_STRING_PTR,
- offsetof(rlm_rest_t, connect_uri), NULL, "http://localhost/" },
+ { "connect_uri", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_rest_t, connect_uri), NULL },
{ NULL, -1, 0, NULL, NULL }
};
-static int rlm_rest_perform(rlm_rest_t *instance, rlm_rest_section_t *section,
- void *handle, REQUEST *request,
+static int rlm_rest_perform(rlm_rest_t *instance, rlm_rest_section_t *section, void *handle, REQUEST *request,
char const *username, char const *password)
{
- size_t uri_len;
+ ssize_t uri_len;
char *uri = NULL;
int ret;
RDEBUG("Expanding URI components");
/*
- * Build xlat'd URI, this allows REST servers to be specified by
- * request attributes.
+ * Build xlat'd URI, this allows REST servers to be specified by
+ * request attributes.
*/
- uri_len = rest_uri_build(&uri, instance, section, request);
+ uri_len = rest_uri_build(&uri, instance, request, section->uri);
if (uri_len <= 0) return -1;
RDEBUG("Sending HTTP %s to \"%s\"", fr_int2str(http_method_table, section->method, NULL), uri);
/*
- * Configure various CURL options, and initialise the read/write
- * context data.
+ * Configure various CURL options, and initialise the read/write
+ * context data.
*/
ret = rest_request_config(instance, section, request, handle, section->method, section->body,
uri, username, password);
if (ret < 0) return -1;
/*
- * Send the CURL request, pre-parse headers, aggregate incoming
- * HTTP body data into a single contiguous buffer.
+ * Send the CURL request, pre-parse headers, aggregate incoming
+ * HTTP body data into a single contiguous buffer.
*/
ret = rest_request_perform(instance, section, request, handle);
if (ret < 0) return -1;
return 0;
}
-static void rlm_rest_cleanup(rlm_rest_t *instance, rlm_rest_section_t *section,
- void *handle)
+static void rlm_rest_cleanup(rlm_rest_t *instance, rlm_rest_section_t *section, void *handle)
{
rest_request_cleanup(instance, section, handle);
};
-static int parse_sub_section(CONF_SECTION *parent,
- rlm_rest_section_t *config,
- rlm_components_t comp)
+/*
+ * Simple xlat to read text data from a URL
+ */
+static ssize_t rest_xlat(void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t freespace)
{
- CONF_SECTION *cs;
-
- char const *name = section_type_value[comp].section;
+ rlm_rest_t *inst = instance;
+ void *handle;
+ int hcode;
+ int ret;
+ ssize_t len, outlen = 0;
+ char *uri = NULL;
+ char const *body;
+
+ /* There are no configurable parameters other than the URI */
+ static rlm_rest_section_t section = {
+ .name = "xlat",
+ .method = HTTP_METHOD_GET,
+ .body = HTTP_BODY_NONE,
+ .require_auth = false,
+ .timeout = 4,
+ .force_to = HTTP_BODY_PLAIN
+ };
+
+ *out = '\0';
+
+ rad_assert(fmt);
- cs = cf_section_sub_find(parent, name);
- if (!cs) {
- /* TODO: Should really setup section with default values */
- return 0;
- }
+ RDEBUG("Expanding URI components");
- if (cf_section_parse(cs, config, section_config) < 0) {
- return -1;
- }
+ handle = fr_connection_get(inst->conn_pool);
+ if (!handle) return -1;
/*
- * Add section name (Maybe add to headers later?).
+ * Unescape parts of xlat'd URI, this allows REST servers to be specified by
+ * request attributes.
*/
- config->name = name;
+ len = rest_uri_host_unescape(&uri, instance, request, handle, fmt);
+ if (len <= 0) {
+ outlen = -1;
+ goto end;
+ }
+
+ RDEBUG("Sending HTTP %s to \"%s\"", fr_int2str(http_method_table, section.method, NULL), uri);
/*
- * Sanity check
+ * Configure various CURL options, and initialise the read/write
+ * context data.
+ *
+ * @todo We could extract the User-Name and password from the URL string.
*/
- if ((config->username && !config->password) || (!config->username && config->password)) {
- cf_log_err_cs(cs, "'username' and 'password' must both be set or both be absent");
-
- return -1;
- }
+ ret = rest_request_config(instance, §ion, request, handle, section.method, section.body,
+ uri, NULL, NULL);
+ talloc_free(uri);
+ if (ret < 0) return -1;
/*
- * Convert HTTP method auth and body type strings into their
- * integer equivalents.
+ * Send the CURL request, pre-parse headers, aggregate incoming
+ * HTTP body data into a single contiguous buffer.
*/
- config->auth = fr_str2int(http_auth_table, config->auth_str, HTTP_AUTH_UNKNOWN);
- if (config->auth == HTTP_AUTH_UNKNOWN) {
- cf_log_err_cs(cs, "Unknown HTTP auth type '%s'", config->auth_str);
- return -1;
- } else if ((config->auth != HTTP_AUTH_NONE) && !http_curl_auth[config->auth]) {
- cf_log_err_cs(cs, "Unsupported HTTP auth type \"%s\", check libcurl version, OpenSSL build "
- "configuration, then recompile this module", config->auth_str);
-
- return -1;
- }
-
- config->method = fr_str2int(http_method_table, config->method_str,
- HTTP_METHOD_CUSTOM);
+ ret = rest_request_perform(instance, §ion, request, handle);
+ if (ret < 0) return -1;
- config->body = fr_str2int(http_body_type_table, config->body_str,
- HTTP_BODY_UNKNOWN);
+ hcode = rest_get_handle_code(handle);
+ switch (hcode) {
+ case 404:
+ case 410:
+ case 403:
+ case 401:
+ outlen = -1;
+ goto end;
- if (config->body == HTTP_BODY_UNKNOWN) {
- cf_log_err_cs(cs, "Unknown HTTP body type '%s'",
- config->body_str);
- return -1;
- }
+ case 204:
+ goto end;
- if (http_body_type_supported[config->body] == HTTP_BODY_UNSUPPORTED) {
- cf_log_err_cs(cs, "Unsupported HTTP body type \"%s\""
- ", please submit patches",
- config->body_str);
- return -1;
+ default:
+ /*
+ * Attempt to parse content if there was any.
+ */
+ if ((hcode >= 200) && (hcode < 300)) {
+ break;
+ } else if (hcode < 500) {
+ outlen = -2;
+ goto end;
+ } else {
+ outlen = -1;
+ goto end;
+ }
}
- return 1;
-}
-
-/*
- * Do any per-module initialization that is separate to each
- * configured instance of the module. e.g. set up connections
- * to external databases, read configuration files, set up
- * dictionary entries, etc.
- *
- * If configuration information is given in the config section
- * that must be referenced in later calls, store a handle to it
- * in *instance otherwise put a null pointer there.
- */
-static int mod_instantiate(CONF_SECTION *conf, void *instance)
-{
- rlm_rest_t *inst = instance;
- char const *xlat_name;
-
- xlat_name = cf_section_name2(conf);
- if (!xlat_name) {
- xlat_name = cf_section_name1(conf);
+ len = rest_get_handle_data(&body, handle);
+ if ((size_t) len >= freespace) {
+ REDEBUG("Insufficient space to write HTTP response, needed %zu bytes, have %zu bytes", len + 1,
+ freespace);
+ outlen = -1;
+ goto end;
}
-
- inst->xlat_name = xlat_name;
-
- /*
- * Parse sub-section configs.
- */
- if (
- (parse_sub_section(conf, &inst->authorize,
- RLM_COMPONENT_AUTZ) < 0) ||
- (parse_sub_section(conf, &inst->authenticate,
- RLM_COMPONENT_AUTH) < 0) ||
- (parse_sub_section(conf, &inst->accounting,
- RLM_COMPONENT_ACCT) < 0) ||
- (parse_sub_section(conf, &inst->checksimul,
- RLM_COMPONENT_SESS) < 0) ||
- (parse_sub_section(conf, &inst->postauth,
- RLM_COMPONENT_POST_AUTH) < 0))
- {
- return -1;
+ if (len > 0) {
+ outlen = len;
+ strlcpy(out, body, len + 1); /* strlcpy takes the size of the buffer */
}
- /*
- * Initialise REST libraries.
- */
- if (rest_init(inst) < 0) {
- return -1;
- }
+end:
+ rlm_rest_cleanup(instance, §ion, handle);
- inst->conn_pool = fr_connection_pool_init(conf, inst, mod_conn_create, mod_conn_alive, mod_conn_delete, NULL);
- if (!inst->conn_pool) {
- return -1;
- }
+ fr_connection_release(inst->conn_pool, handle);
- return 0;
+ return outlen;
}
/*
* from the database. The authentication code only needs to check
* the password, the rest is done here.
*/
-static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
{
rlm_rest_t *inst = instance;
rlm_rest_section_t *section = &inst->authorize;
hcode = rest_get_handle_code(handle);
switch (hcode) {
- case 404:
- case 410:
- rcode = RLM_MODULE_NOTFOUND;
+ case 404:
+ case 410:
+ rcode = RLM_MODULE_NOTFOUND;
+ break;
+
+ case 403:
+ rcode = RLM_MODULE_USERLOCK;
+ break;
+
+ case 401:
+ /*
+ * Attempt to parse content if there was any.
+ */
+ ret = rest_response_decode(inst, section, request, handle);
+ if (ret < 0) {
+ rcode = RLM_MODULE_FAIL;
break;
- case 403:
- rcode = RLM_MODULE_USERLOCK;
- break;
- case 401:
- /*
- * Attempt to parse content if there was any.
- */
- ret = rest_request_decode(inst, section, request, handle);
- if (ret < 0) {
- rcode = RLM_MODULE_FAIL;
- break;
- }
+ }
- rcode = RLM_MODULE_REJECT;
- break;
- case 204:
- rcode = RLM_MODULE_OK;
+ rcode = RLM_MODULE_REJECT;
+ break;
+
+ case 204:
+ rcode = RLM_MODULE_OK;
+ break;
+
+ default:
+ /*
+ * Attempt to parse content if there was any.
+ */
+ if ((hcode >= 200) && (hcode < 300)) {
+ ret = rest_response_decode(inst, section, request, handle);
+ if (ret < 0) rcode = RLM_MODULE_FAIL;
+ else if (ret == 0) rcode = RLM_MODULE_OK;
+ else rcode = RLM_MODULE_UPDATED;
break;
- default:
- /*
- * Attempt to parse content if there was any.
- */
- if ((hcode >= 200) && (hcode < 300)) {
- ret = rest_request_decode(inst, section, request, handle);
- if (ret < 0) rcode = RLM_MODULE_FAIL;
- else if (ret == 0) rcode = RLM_MODULE_OK;
- else rcode = RLM_MODULE_UPDATED;
- break;
- } else if (hcode < 500) {
- rcode = RLM_MODULE_INVALID;
- } else {
- rcode = RLM_MODULE_FAIL;
- }
+ } else if (hcode < 500) {
+ rcode = RLM_MODULE_INVALID;
+ } else {
+ rcode = RLM_MODULE_FAIL;
+ }
}
end:
/*
* Authenticate the user with the given password.
*/
-static rlm_rcode_t mod_authenticate(void *instance, UNUSED REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, UNUSED REQUEST *request)
{
rlm_rest_t *inst = instance;
rlm_rest_section_t *section = &inst->authenticate;
VALUE_PAIR const *username;
VALUE_PAIR const *password;
- username = pairfind(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
- if (!username) {
+ username = request->username;
+ if (!request->username) {
REDEBUG("Can't perform authentication, 'User-Name' attribute not found in the request");
return RLM_MODULE_INVALID;
}
- password = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
- if (!password) {
- REDEBUG("Can't perform authentication, 'Cleartext-Password' attribute not found in the control list");
-
+ password = request->password;
+ if (!password ||
+ (password->da->attr != PW_USER_PASSWORD)) {
+ REDEBUG("You set 'Auth-Type = REST' for a request that does not contain a User-Password attribute!");
return RLM_MODULE_INVALID;
}
hcode = rest_get_handle_code(handle);
switch (hcode) {
- case 404:
- case 410:
- rcode = RLM_MODULE_NOTFOUND;
+ case 404:
+ case 410:
+ rcode = RLM_MODULE_NOTFOUND;
+ break;
+
+ case 403:
+ rcode = RLM_MODULE_USERLOCK;
+ break;
+
+ case 401:
+ /*
+ * Attempt to parse content if there was any.
+ */
+ ret = rest_response_decode(inst, section, request, handle);
+ if (ret < 0) {
+ rcode = RLM_MODULE_FAIL;
break;
- case 403:
- rcode = RLM_MODULE_USERLOCK;
- break;
- case 401:
- /*
- * Attempt to parse content if there was any.
- */
- ret = rest_request_decode(inst, section, request, handle);
- if (ret < 0) {
- rcode = RLM_MODULE_FAIL;
- break;
- }
+ }
- rcode = RLM_MODULE_REJECT;
- break;
- case 204:
- rcode = RLM_MODULE_OK;
+ rcode = RLM_MODULE_REJECT;
+ break;
+
+ case 204:
+ rcode = RLM_MODULE_OK;
+ break;
+
+ default:
+ /*
+ * Attempt to parse content if there was any.
+ */
+ if ((hcode >= 200) && (hcode < 300)) {
+ ret = rest_response_decode(inst, section, request, handle);
+ if (ret < 0) rcode = RLM_MODULE_FAIL;
+ else if (ret == 0) rcode = RLM_MODULE_OK;
+ else rcode = RLM_MODULE_UPDATED;
break;
- default:
- /*
- * Attempt to parse content if there was any.
- */
- if ((hcode >= 200) && (hcode < 300)) {
- ret = rest_request_decode(inst, section, request, handle);
- if (ret < 0) rcode = RLM_MODULE_FAIL;
- else if (ret == 0) rcode = RLM_MODULE_OK;
- else rcode = RLM_MODULE_UPDATED;
- break;
- } else if (hcode < 500) {
- rcode = RLM_MODULE_INVALID;
- } else {
- rcode = RLM_MODULE_FAIL;
- }
+ } else if (hcode < 500) {
+ rcode = RLM_MODULE_INVALID;
+ } else {
+ rcode = RLM_MODULE_FAIL;
+ }
}
end:
}
/*
- * Write accounting information to this modules database.
+ * Send accounting info to a REST API endpoint
*/
-static rlm_rcode_t mod_accounting(void *instance, UNUSED REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, UNUSED REQUEST *request)
{
rlm_rest_t *inst = instance;
rlm_rest_section_t *section = &inst->accounting;
} else if (hcode == 204) {
rcode = RLM_MODULE_OK;
} else if ((hcode >= 200) && (hcode < 300)) {
- ret = rest_request_decode(inst, section, request, handle);
+ ret = rest_response_decode(inst, section, request, handle);
if (ret < 0) rcode = RLM_MODULE_FAIL;
else if (ret == 0) rcode = RLM_MODULE_OK;
else rcode = RLM_MODULE_UPDATED;
rcode = RLM_MODULE_INVALID;
}
- end:
+end:
+ rlm_rest_cleanup(inst, section, handle);
+
+ fr_connection_release(inst->conn_pool, handle);
+
+ return rcode;
+}
+
+/*
+ * Send post-auth info to a REST API endpoint
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, UNUSED REQUEST *request)
+{
+ rlm_rest_t *inst = instance;
+ rlm_rest_section_t *section = &inst->post_auth;
+
+ void *handle;
+ int hcode;
+ int rcode = RLM_MODULE_OK;
+ int ret;
+
+ handle = fr_connection_get(inst->conn_pool);
+ if (!handle) return RLM_MODULE_FAIL;
+
+ ret = rlm_rest_perform(inst, section, handle, request, NULL, NULL);
+ if (ret < 0) {
+ rcode = RLM_MODULE_FAIL;
+ goto end;
+ }
+ hcode = rest_get_handle_code(handle);
+ if (hcode >= 500) {
+ rcode = RLM_MODULE_FAIL;
+ } else if (hcode == 204) {
+ rcode = RLM_MODULE_OK;
+ } else if ((hcode >= 200) && (hcode < 300)) {
+ ret = rest_response_decode(inst, section, request, handle);
+ if (ret < 0) rcode = RLM_MODULE_FAIL;
+ else if (ret == 0) rcode = RLM_MODULE_OK;
+ else rcode = RLM_MODULE_UPDATED;
+ } else {
+ rcode = RLM_MODULE_INVALID;
+ }
+
+end:
rlm_rest_cleanup(inst, section, handle);
fr_connection_release(inst->conn_pool, handle);
return rcode;
}
+static int parse_sub_section(CONF_SECTION *parent, rlm_rest_section_t *config, rlm_components_t comp)
+{
+ CONF_SECTION *cs;
+
+ char const *name = section_type_value[comp].section;
+
+ cs = cf_section_sub_find(parent, name);
+ if (!cs) {
+ /* TODO: Should really setup section with default values */
+ return 0;
+ }
+
+ if (cf_section_parse(cs, config, section_config) < 0) {
+ return -1;
+ }
+
+ /*
+ * Add section name (Maybe add to headers later?).
+ */
+ config->name = name;
+
+ /*
+ * Sanity check
+ */
+ if ((config->username && !config->password) || (!config->username && config->password)) {
+ cf_log_err_cs(cs, "'username' and 'password' must both be set or both be absent");
+
+ return -1;
+ }
+
+ /*
+ * Convert HTTP method auth and body type strings into their integer equivalents.
+ */
+ config->auth = fr_str2int(http_auth_table, config->auth_str, HTTP_AUTH_UNKNOWN);
+ if (config->auth == HTTP_AUTH_UNKNOWN) {
+ cf_log_err_cs(cs, "Unknown HTTP auth type '%s'", config->auth_str);
+
+ return -1;
+ } else if ((config->auth != HTTP_AUTH_NONE) && !http_curl_auth[config->auth]) {
+ cf_log_err_cs(cs, "Unsupported HTTP auth type \"%s\", check libcurl version, OpenSSL build "
+ "configuration, then recompile this module", config->auth_str);
+
+ return -1;
+ }
+
+ config->method = fr_str2int(http_method_table, config->method_str, HTTP_METHOD_CUSTOM);
+
+ /*
+ * We don't have any custom user data, so we need to select the right encoder based
+ * on the body type.
+ *
+ * To make this slightly more/less confusing, we accept both canonical body_types,
+ * and content_types.
+ */
+ if (!config->data) {
+ config->body = fr_str2int(http_body_type_table, config->body_str, HTTP_BODY_UNKNOWN);
+ if (config->body == HTTP_BODY_UNKNOWN) {
+ config->body = fr_str2int(http_content_type_table, config->body_str, HTTP_BODY_UNKNOWN);
+ }
+
+ if (config->body == HTTP_BODY_UNKNOWN) {
+ cf_log_err_cs(cs, "Unknown HTTP body type '%s'", config->body_str);
+ return -1;
+ }
+
+ switch (http_body_type_supported[config->body])
+ {
+ case HTTP_BODY_UNSUPPORTED:
+ cf_log_err_cs(cs, "Unsupported HTTP body type \"%s\", please submit patches",
+ config->body_str);
+ return -1;
+
+ case HTTP_BODY_INVALID:
+ cf_log_err_cs(cs, "Invalid HTTP body type. \"%s\" is not a valid web API data "
+ "markup format", config->body_str);
+ return -1;
+
+ default:
+ break;
+ }
+ /*
+ * We have custom body data so we set HTTP_BODY_CUSTOM, but also need to try and
+ * figure out what content-type to use. So if they've used the canonical form we
+ * need to convert it back into a proper HTTP content_type value.
+ */
+ } else {
+ http_body_type_t body;
+
+ config->body = HTTP_BODY_CUSTOM;
+
+ body = fr_str2int(http_body_type_table, config->body_str, HTTP_BODY_UNKNOWN);
+ if (body != HTTP_BODY_UNKNOWN) {
+ config->body_str = fr_int2str(http_content_type_table, body, config->body_str);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Do any per-module initialization that is separate to each
+ * configured instance of the module. e.g. set up connections
+ * to external databases, read configuration files, set up
+ * dictionary entries, etc.
+ *
+ * If configuration information is given in the config section
+ * that must be referenced in later calls, store a handle to it
+ * in *instance otherwise put a null pointer there.
+ */
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ rlm_rest_t *inst = instance;
+ char const *xlat_name;
+
+ xlat_name = cf_section_name2(conf);
+ if (!xlat_name) {
+ xlat_name = cf_section_name1(conf);
+ }
+
+ inst->xlat_name = xlat_name;
+
+ /*
+ * Register the rest xlat function
+ */
+ xlat_register(inst->xlat_name, rest_xlat, rest_uri_escape, inst);
+
+ /*
+ * Parse sub-section configs.
+ */
+ if (
+ (parse_sub_section(conf, &inst->authorize, RLM_COMPONENT_AUTZ) < 0) ||
+ (parse_sub_section(conf, &inst->authenticate, RLM_COMPONENT_AUTH) < 0) ||
+ (parse_sub_section(conf, &inst->accounting, RLM_COMPONENT_ACCT) < 0) ||
+
+/* @todo add behaviour for checksimul */
+/* (parse_sub_section(conf, &inst->checksimul, RLM_COMPONENT_SESS) < 0) || */
+ (parse_sub_section(conf, &inst->post_auth, RLM_COMPONENT_POST_AUTH) < 0))
+ {
+ return -1;
+ }
+
+ /*
+ * Initialise REST libraries.
+ */
+ if (rest_init(inst) < 0) {
+ return -1;
+ }
+
+ inst->conn_pool = fr_connection_pool_init(conf, inst, mod_conn_create, mod_conn_alive, mod_conn_delete, NULL);
+ if (!inst->conn_pool) {
+ return -1;
+ }
+
+ return 0;
+}
+
/*
* Only free memory we allocated. The strings allocated via
* cf_section_parse() do not need to be freed.
fr_connection_pool_delete(inst->conn_pool);
+ xlat_unregister(inst->xlat_name, rest_xlat, instance);
+
/* Free any memory used by libcurl */
rest_cleanup();
NULL, /* checksimul */
NULL, /* pre-proxy */
NULL, /* post-proxy */
- NULL /* post-auth */
+ mod_post_auth /* post-auth */
},
};
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
CPP C preprocessor
RUBY Absolute path to ruby executable
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test -z "$RUBY"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ruby executable path has been provided" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ruby executable path has been provided" >&5
$as_echo_n "checking whether ruby executable path has been provided... " >&6; }
# Check whether --with-ruby was given.
if test "${with_ruby+set}" = set; then :
withval=$with_ruby;
- if test "$withval" != yes && test "$withval" != no; then :
+ if test "$withval" != yes && test "$withval" != no; then :
- RUBY="$withval"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY" >&5
+ RUBY="$withval"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY" >&5
$as_echo "$RUBY" >&6; }
else
- RUBY=""
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+ RUBY=""
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
- if test "$withval" != no; then :
+ if test "$withval" != no; then :
- # Extract the first word of "ruby", so it can be a program name with args.
+ # Extract the first word of "ruby", so it can be a program name with args.
set dummy ruby; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
- # Extract the first word of "ruby", so it can be a program name with args.
+ # Extract the first word of "ruby", so it can be a program name with args.
set dummy ruby; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_path_SED+:} false; then :
$as_echo_n "(cached) " >&6
else
- ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+ ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
for ac_i in 1 2 3 4 5 6 7; do
ac_script="$ac_script$as_nl$ac_script"
done
if test -n "$RUBY"; then :
- ax_ruby_version="1.8"
+ ax_ruby_version="1.8"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ruby version" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ruby version" >&5
$as_echo_n "checking for ruby version... " >&6; }
- ruby_version=`$RUBY --version 2>&1 | $GREP "^ruby " | $SED -e 's/^.* \([0-9]*\.[0-9]*\.[0-9]*\) .*/\1/'`
+ ruby_version=`$RUBY --version 2>&1 | $GREP "^ruby " | $SED -e 's/^.* \([0-9]*\.[0-9]*\.[0-9]*\) .*/\1/'`
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ruby_version" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ruby_version" >&5
$as_echo "$ruby_version" >&6; }
RUBY_VERSION=$ruby_version
# digits, and non digits are removed.
ax_compare_version_A=`echo "$ax_ruby_version" | sed -e 's/\([0-9]*\)/Z\1Z/g' \
- -e 's/Z\([0-9]\)Z/Z0\1Z/g' \
- -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \
- -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \
- -e 's/[^0-9]//g'`
+ -e 's/Z\([0-9]\)Z/Z0\1Z/g' \
+ -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \
+ -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \
+ -e 's/[^0-9]//g'`
ax_compare_version_B=`echo "$ruby_version" | sed -e 's/\([0-9]*\)/Z\1Z/g' \
- -e 's/Z\([0-9]\)Z/Z0\1Z/g' \
- -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \
- -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \
- -e 's/[^0-9]//g'`
+ -e 's/Z\([0-9]\)Z/Z0\1Z/g' \
+ -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \
+ -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \
+ -e 's/[^0-9]//g'`
ax_compare_version=`echo "x$ax_compare_version_A
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: could not find the ruby interpreter" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: could not find the ruby interpreter" >&5
$as_echo "$as_me: WARNING: could not find the ruby interpreter" >&2;}
$as_echo_n "checking for the mkmf Ruby package... " >&6; }
ac_mkmf_result=`$RUBY -rmkmf -e ";" 2>&1`
if test -z "$ac_mkmf_result"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ { $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 "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot import Ruby module \"mkmf\".
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot import Ruby module \"mkmf\".
Please check your Ruby installation. The error was:
$ac_distutils_result" >&5
$as_echo "$as_me: WARNING: cannot import Ruby module \"mkmf\".
# Check for Ruby include path
#
if test -z "$RUBY_CFLAGS"; then
- #
- # Check for Ruby cflags
- #
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Ruby cflags" >&5
+ #
+ # Check for Ruby cflags
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Ruby cflags" >&5
$as_echo_n "checking for Ruby cflags... " >&6; }
- if test -z "$RUBY_CFLAGS"; then
- RUBY_CFLAGS=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(CFLAGS))'`
- fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY_CFLAGS" >&5
+ if test -z "$RUBY_CFLAGS"; then
+ RUBY_CFLAGS=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(CFLAGS))'`
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY_CFLAGS" >&5
$as_echo "$RUBY_CFLAGS" >&6; }
- #
- # Check for Ruby include path
- #
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Ruby include path" >&5
+ #
+ # Check for Ruby include path
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Ruby include path" >&5
$as_echo_n "checking for Ruby include path... " >&6; }
- ruby_path=`$RUBY -rmkmf -e 'c = RbConfig::CONFIG; print c.has_key?(%q(rubyhdrdir)) ? \
- c.fetch(%q(rubyhdrdir)) : c.fetch(%q(archdir))'`
-
- ruby_arch=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(arch))'`
-
- if test -n "${ruby_path}"; then
- #
- # For some reason ruby 1.9.1 on linux seems to put its
- # config.h file in ${ruby_path}/${ruby_arch}/ruby/config.h
- # Aside from the fact that it is WRONG to include your own
- # config.h file, it means we can't use the headers unless we
- # add both paths.
- #
- if test -d "${ruby_path}/${ruby_arch}"; then
- ruby_path=" -I${ruby_path} -I${ruby_path}/${ruby_arch}"
- else
- ruby_path=" -I${ruby_path}"
- fi
- fi
-
- RUBY_CFLAGS+="$ruby_path"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ruby_path" >&5
+ ruby_path=`$RUBY -rmkmf -e 'c = RbConfig::CONFIG; print c.has_key?(%q(rubyhdrdir)) ? \
+ c.fetch(%q(rubyhdrdir)) : c.fetch(%q(archdir))'`
+
+ ruby_arch=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(arch))'`
+
+ if test -n "${ruby_path}"; then
+ #
+ # For some reason ruby 1.9.1 on linux seems to put its
+ # config.h file in ${ruby_path}/${ruby_arch}/ruby/config.h
+ # Aside from the fact that it is WRONG to include your own
+ # config.h file, it means we can't use the headers unless we
+ # add both paths.
+ #
+ if test -d "${ruby_path}/${ruby_arch}"; then
+ ruby_path=" -I${ruby_path} -I${ruby_path}/${ruby_arch}"
+ else
+ ruby_path=" -I${ruby_path}"
+ fi
+ fi
+
+ RUBY_CFLAGS+="$ruby_path"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ruby_path" >&5
$as_echo "$ruby_path" >&6; }
fi
if test -z "$RUBY_LDFLAGS"; then
- #
- # Check for Ruby library path
- #
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Ruby library path" >&5
+ #
+ # Check for Ruby library path
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Ruby library path" >&5
$as_echo_n "checking for Ruby library path... " >&6; }
- if test -z "$RUBY_LIBRARY_PATH"; then
- RUBY_LIBRARY_PATH=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(libdir))'`
- if test -n "${RUBY_LIBRARY_PATH}"; then
- RUBY_LIBRARY_PATH=" -L$RUBY_LIBRARY_PATH"
- fi
- fi
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY_LIBRARY_PATH" >&5
+ if test -z "$RUBY_LIBRARY_PATH"; then
+ RUBY_LIBRARY_PATH=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(libdir))'`
+ if test -n "${RUBY_LIBRARY_PATH}"; then
+ RUBY_LIBRARY_PATH=" -L$RUBY_LIBRARY_PATH"
+ fi
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY_LIBRARY_PATH" >&5
$as_echo "$RUBY_LIBRARY_PATH" >&6; }
- #
- # Check for Ruby linking flags
- #
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Ruby linking flags" >&5
+ #
+ # Check for Ruby linking flags
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Ruby linking flags" >&5
$as_echo_n "checking for Ruby linking flags... " >&6; }
- RUBY_LDFLAGS=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(LIBRUBYARG_SHARED))'`
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY_LDFLAGS" >&5
+ RUBY_LDFLAGS=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(LIBRUBYARG_SHARED))'`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY_LDFLAGS" >&5
$as_echo "$RUBY_LDFLAGS" >&6; }
- RUBY_LDFLAGS="${RUBY_LIBRARY_PATH} ${RUBY_LDFLAGS}"
+ RUBY_LDFLAGS="${RUBY_LIBRARY_PATH} ${RUBY_LDFLAGS}"
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Ruby site-packages path" >&5
$as_echo_n "checking for Ruby site-packages path... " >&6; }
if test -z "$RUBY_SITE_PKG"; then
- RUBY_SITE_PKG=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(sitearchdir))'`
+ RUBY_SITE_PKG=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(sitearchdir))'`
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY_SITE_PKG" >&5
$as_echo "$RUBY_SITE_PKG" >&6; }
if test -n "$RUBY_VERSION"; then
mod_cflags=$(echo "${RUBY_CFLAGS}" | sed 's/-I[ ]*/-isystem /g' | sed 's/-arch [^ ]*[ ]*//g')
- { $as_echo "$as_me:${as_lineno-$LINENO}: Sanitized cflags are \"${mod_cflags}\"" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Sanitized cflags are \"${mod_cflags}\"" >&5
$as_echo "$as_me: Sanitized cflags are \"${mod_cflags}\"" >&6;}
mod_ldflags="${RUBY_LDFLAGS} ${RUBY_EXTRA_LIBS}"
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
if test -n "$RUBY_VERSION"; then
mod_cflags=[$(echo "${RUBY_CFLAGS}" | sed 's/-I[ ]*/-isystem /g' | sed 's/-arch [^ ]*[ ]*//g')]
- AC_MSG_NOTICE([Sanitized cflags are \"${mod_cflags}\"])
-
+ AC_MSG_NOTICE([Sanitized cflags are \"${mod_cflags}\"])
+
mod_ldflags="${RUBY_LDFLAGS} ${RUBY_EXTRA_LIBS}"
else
fail="ruby"
#This is example radius.rb script
module Radiusd
def Radiusd.instantiate(arg)
- radlog(L_DBG,"[ruby]Running ruby instantiate")
- p arg
- return Radiusd::RLM_MODULE_OK
+ radlog(L_DBG,"[ruby]Running ruby instantiate")
+ p arg
+ return Radiusd::RLM_MODULE_OK
end
def Radiusd.authenticate(arg)
- radlog(L_DBG,"[ruby]Running ruby authenticate")
- p arg
- return Radiusd::RLM_MODULE_NOOP
+ radlog(L_DBG,"[ruby]Running ruby authenticate")
+ p arg
+ return Radiusd::RLM_MODULE_NOOP
end
def Radiusd.authorize(arg)
- radlog(L_DBG,"[ruby]Running ruby authorize")
- p arg
- #Here we return Cleartext-Password, which could have been retrieved from DB.
- return [Radiusd::RLM_MODULE_UPDATED, [],[["Cleartext-Password","pass"]]]
+ radlog(L_DBG,"[ruby]Running ruby authorize")
+ p arg
+ #Here we return Cleartext-Password, which could have been retrieved from DB.
+ return [Radiusd::RLM_MODULE_UPDATED, [],[["Cleartext-Password","pass"]]]
end
def Radiusd.accounting(arg)
- radlog(L_DBG,"[ruby]Running ruby accounting")
- p arg
- return Radiusd::RLM_MODULE_NOOP
+ radlog(L_DBG,"[ruby]Running ruby accounting")
+ p arg
+ return Radiusd::RLM_MODULE_NOOP
end
end
AC_REQUIRE([AC_PROG_GREP])
AS_IF([test -n "$RUBY"],[
- ax_ruby_version="$1"
+ ax_ruby_version="$1"
- AC_MSG_CHECKING([for ruby version])
- changequote(<<,>>)
- ruby_version=`$RUBY --version 2>&1 | $GREP "^ruby " | $SED -e 's/^.* \([0-9]*\.[0-9]*\.[0-9]*\) .*/\1/'`
- changequote([,])
- AC_MSG_RESULT($ruby_version)
+ AC_MSG_CHECKING([for ruby version])
+ changequote(<<,>>)
+ ruby_version=`$RUBY --version 2>&1 | $GREP "^ruby " | $SED -e 's/^.* \([0-9]*\.[0-9]*\.[0-9]*\) .*/\1/'`
+ changequote([,])
+ AC_MSG_RESULT($ruby_version)
AC_SUBST([RUBY_VERSION],[$ruby_version])
- AX_COMPARE_VERSION([$ax_ruby_version],[le],[$ruby_version],[
+ AX_COMPARE_VERSION([$ax_ruby_version],[le],[$ruby_version],[
:
- $2
- ],[
+ $2
+ ],[
:
- $3
- ])
+ $3
+ ])
],[
- AC_MSG_WARN([could not find the ruby interpreter])
- $3
+ AC_MSG_WARN([could not find the ruby interpreter])
+ $3
])
])
AC_MSG_CHECKING([for the mkmf Ruby package])
ac_mkmf_result=`$RUBY -rmkmf -e ";" 2>&1`
if test -z "$ac_mkmf_result"; then
- AC_MSG_RESULT([yes])
+ AC_MSG_RESULT([yes])
else
- AC_MSG_RESULT([no])
- AC_MSG_WARN([cannot import Ruby module "mkmf".
+ AC_MSG_RESULT([no])
+ AC_MSG_WARN([cannot import Ruby module "mkmf".
Please check your Ruby installation. The error was:
$ac_distutils_result])
fi
# Check for Ruby include path
#
if test -z "$RUBY_CFLAGS"; then
- #
- # Check for Ruby cflags
- #
- AC_MSG_CHECKING([for Ruby cflags])
- if test -z "$RUBY_CFLAGS"; then
- RUBY_CFLAGS=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(CFLAGS))'`
- fi
- AC_MSG_RESULT([$RUBY_CFLAGS])
+ #
+ # Check for Ruby cflags
+ #
+ AC_MSG_CHECKING([for Ruby cflags])
+ if test -z "$RUBY_CFLAGS"; then
+ RUBY_CFLAGS=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(CFLAGS))'`
+ fi
+ AC_MSG_RESULT([$RUBY_CFLAGS])
- #
- # Check for Ruby include path
- #
- AC_MSG_CHECKING([for Ruby include path])
- ruby_path=`$RUBY -rmkmf -e 'c = RbConfig::CONFIG; print c.has_key?(%q(rubyhdrdir)) ? \
- c.fetch(%q(rubyhdrdir)) : c.fetch(%q(archdir))'`
-
- ruby_arch=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(arch))'`
-
- if test -n "${ruby_path}"; then
- #
- # For some reason ruby 1.9.1 on linux seems to put its
- # config.h file in ${ruby_path}/${ruby_arch}/ruby/config.h
- # Aside from the fact that it is WRONG to include your own
- # config.h file, it means we can't use the headers unless we
- # add both paths.
- #
- if test -d "${ruby_path}/${ruby_arch}"; then
- ruby_path=" -I${ruby_path} -I${ruby_path}/${ruby_arch}"
- else
- ruby_path=" -I${ruby_path}"
- fi
- fi
-
- RUBY_CFLAGS+="$ruby_path"
- AC_MSG_RESULT([$ruby_path])
+ #
+ # Check for Ruby include path
+ #
+ AC_MSG_CHECKING([for Ruby include path])
+ ruby_path=`$RUBY -rmkmf -e 'c = RbConfig::CONFIG; print c.has_key?(%q(rubyhdrdir)) ? \
+ c.fetch(%q(rubyhdrdir)) : c.fetch(%q(archdir))'`
+
+ ruby_arch=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(arch))'`
+
+ if test -n "${ruby_path}"; then
+ #
+ # For some reason ruby 1.9.1 on linux seems to put its
+ # config.h file in ${ruby_path}/${ruby_arch}/ruby/config.h
+ # Aside from the fact that it is WRONG to include your own
+ # config.h file, it means we can't use the headers unless we
+ # add both paths.
+ #
+ if test -d "${ruby_path}/${ruby_arch}"; then
+ ruby_path=" -I${ruby_path} -I${ruby_path}/${ruby_arch}"
+ else
+ ruby_path=" -I${ruby_path}"
+ fi
+ fi
+
+ RUBY_CFLAGS+="$ruby_path"
+ AC_MSG_RESULT([$ruby_path])
fi
AC_SUBST([RUBY_CFLAGS])
if test -z "$RUBY_LDFLAGS"; then
- #
- # Check for Ruby library path
- #
- AC_MSG_CHECKING([for Ruby library path])
- if test -z "$RUBY_LIBRARY_PATH"; then
- RUBY_LIBRARY_PATH=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(libdir))'`
- if test -n "${RUBY_LIBRARY_PATH}"; then
- RUBY_LIBRARY_PATH=" -L$RUBY_LIBRARY_PATH"
- fi
- fi
-
- AC_MSG_RESULT([$RUBY_LIBRARY_PATH])
-
- #
- # Check for Ruby linking flags
- #
- AC_MSG_CHECKING([for Ruby linking flags])
+ #
+ # Check for Ruby library path
+ #
+ AC_MSG_CHECKING([for Ruby library path])
+ if test -z "$RUBY_LIBRARY_PATH"; then
+ RUBY_LIBRARY_PATH=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(libdir))'`
+ if test -n "${RUBY_LIBRARY_PATH}"; then
+ RUBY_LIBRARY_PATH=" -L$RUBY_LIBRARY_PATH"
+ fi
+ fi
+
+ AC_MSG_RESULT([$RUBY_LIBRARY_PATH])
+
+ #
+ # Check for Ruby linking flags
+ #
+ AC_MSG_CHECKING([for Ruby linking flags])
- RUBY_LDFLAGS=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(LIBRUBYARG_SHARED))'`
- AC_MSG_RESULT([$RUBY_LDFLAGS])
+ RUBY_LDFLAGS=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(LIBRUBYARG_SHARED))'`
+ AC_MSG_RESULT([$RUBY_LDFLAGS])
- RUBY_LDFLAGS="${RUBY_LIBRARY_PATH} ${RUBY_LDFLAGS}"
+ RUBY_LDFLAGS="${RUBY_LIBRARY_PATH} ${RUBY_LDFLAGS}"
fi
AC_SUBST([RUBY_LDFLAGS])
#
AC_MSG_CHECKING([for Ruby site-packages path])
if test -z "$RUBY_SITE_PKG"; then
- RUBY_SITE_PKG=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(sitearchdir))'`
+ RUBY_SITE_PKG=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(sitearchdir))'`
fi
AC_MSG_RESULT([$RUBY_SITE_PKG])
AC_SUBST([RUBY_SITE_PKG])
ac_save_CFLAGS="$CFLAGS"
CFLAGS="$ac_save_CFLAGS $RUBY_CFLAGS"
AC_LINK_IFELSE(
- [AC_LANG_PROGRAM([#include <ruby.h>],[ruby_init()])],
- [rubyexists=yes],
- [rubyexists=no])
+ [AC_LANG_PROGRAM([#include <ruby.h>],[ruby_init()])],
+ [rubyexists=yes],
+ [rubyexists=no])
AC_MSG_RESULT([$rubyexists])
#endif
RLM_RUBY_STRUCT(detach);
- char *filename;
- char *module_name;
+ char const *filename;
+ char const *module_name;
VALUE module;
} rlm_ruby_t;
* buffer over-flows.
*/
static const CONF_PARSER module_config[] = {
- { "filename", PW_TYPE_FILE_INPUT | PW_TYPE_REQUIRED,
- offsetof(struct rlm_ruby_t, filename), NULL, NULL},
- { "module", PW_TYPE_STRING_PTR,
- offsetof(struct rlm_ruby_t, module_name), NULL, "Radiusd"},
- { NULL, -1, 0, NULL, NULL} /* end of module_config */
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_REQUIRED, struct rlm_ruby_t, filename), NULL },
+ { "module", FR_CONF_OFFSET(PW_TYPE_STRING, struct rlm_ruby_t, module_name), "Radiusd" },
+ { NULL, -1, 0, NULL, NULL } /* end of module_config */
};
*/
#define BUF_SIZE 1024
-static rlm_rcode_t do_ruby(REQUEST *request, unsigned long func,
- VALUE module, char const *function_name) {
+static rlm_rcode_t CC_HINT(nonnull (4)) do_ruby(REQUEST *request, unsigned long func,
+ VALUE module, char const *function_name)
+{
rlm_rcode_t rcode = RLM_MODULE_OK;
vp_cursor_t cursor;
}
n_tuple = 0;
-
if (request) {
- for (vp = paircursor(&cursor, &request->packet->vps);
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
vp;
- vp = pairnext(&cursor)) {
- n_tuple++;
+ vp = fr_cursor_next(&cursor)) {
+ n_tuple++;
}
}
-
/*
Creating ruby array, that contains arrays of [name,value]
Maybe we should use hash instead? Can this names repeat?
*/
rb_request = rb_ary_new2(n_tuple);
+
if (request) {
- for (vp = paircursor(&cursor, &request->packet->vps);
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
VALUE tmp = rb_ary_new2(2);
/* The name. logic from vp_prints, lib/print.c */
*/
if (TYPE(rb_result) == T_ARRAY) {
if (!FIXNUM_P(rb_ary_entry(rb_result, 0))) {
- REDEBUG("First element of an array was not a "
- "FIXNUM (Which has to be a return_value)");
+ ERROR("First element of an array was not a FIXNUM (Which has to be a return_value)");
rcode = RLM_MODULE_FAIL;
goto finish;
*/
module = inst->module = rb_define_module(inst->module_name);
if (!module) {
- EDEBUG("Ruby rb_define_module failed");
+ ERROR("Ruby rb_define_module failed");
return -1;
}
DEBUG("Loading file %s...", inst->filename);
rb_load_protect(rb_str_new2(inst->filename), 0, &status);
if (status) {
- EDEBUG("Error loading file %s status: %d", inst->filename, status);
+ ERROR("Error loading file %s status: %d", inst->filename, status);
return -1;
}
return do_ruby(NULL, inst->func_instantiate, inst->module, "instantiate");
}
-#define RLM_RUBY_FUNC(foo) static rlm_rcode_t mod_##foo(void *instance, REQUEST *request) \
+#define RLM_RUBY_FUNC(foo) static rlm_rcode_t CC_HINT(nonnull) mod_##foo(void *instance, REQUEST *request) \
{ \
return do_ruby(request, \
((struct rlm_ruby_t *)instance)->func_##foo,((struct rlm_ruby_t *)instance)->module, \
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-securid-include-dir=DIR
- Directory where the securid includes may be found
+ Directory where the securid includes may be found
--with-securid-lib-dir=DIR
- Directory where the securid libraries may be found
+ Directory where the securid libraries may be found
--with-securid-dir=DIR Base directory where securid is installed
Some influential environment variables:
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
if test x$with_rlm_securid != xno; then
- securid_include_dir=
+ securid_include_dir=
# Check whether --with-securid-include-dir was given.
if test "${with_securid_include_dir+set}" = set; then :
fi
- securid_lib_dir=
+ securid_lib_dir=
# Check whether --with-securid-lib-dir was given.
if test "${with_securid_lib_dir+set}" = set; then :
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=acexport.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
fi
- smart_try_dir="$securid_lib_dir"
+ smart_try_dir="$securid_lib_dir"
sm_lib_safe=`echo "aceclnt" | sed 'y%./+-%__p_%'`
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-laceclnt"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-laceclnt"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libaceclnt${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libaceclnt.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
pthread_mutex_lock(&(inst->session_mutex));
- for (node = inst->session_head; node != NULL; node = next) {
+ for (node = inst->session_head; node != NULL; node = next) {
next = node->next;
securid_session_free(inst,request,node);
}
* Since we're adding it to the list, we guess that this means
* the packet needs a State attribute. So add one.
*/
-int securid_sessionlist_add(rlm_securid_t *inst,REQUEST *request,
- SECURID_SESSION *session)
+int securid_sessionlist_add(rlm_securid_t *inst,REQUEST *request, SECURID_SESSION *session)
{
int status = 0;
VALUE_PAIR *state;
- rad_assert(session != NULL);
- rad_assert(request != NULL);
-
/*
* The time at which this request was made was the time
* at which it was received by the RADIUS server.
* Might not have been there.
*/
if (!session) {
- ERROR("rlm_securid: No SECURID session matching the State variable.");
+ ERROR("rlm_securid: No SECURID session matching the State variable");
return NULL;
}
* Delete old sessions from the list
*
*/
- while((session = inst->session_head)) {
+ while((session = inst->session_head)) {
if ((timestamp - session->timestamp) > inst->timer_limit) {
rbnode_t *node;
node = rbtree_find(inst->session_tree, session);
static const CONF_PARSER module_config[] = {
- { "timer_expire", PW_TYPE_INTEGER,
- offsetof(rlm_securid_t, timer_limit), NULL, "600"},
- { "max_sessions", PW_TYPE_INTEGER,
- offsetof(rlm_securid_t, max_sessions), NULL, "2048"},
- { "max_trips_per_session", PW_TYPE_INTEGER,
- offsetof(rlm_securid_t, max_trips_per_session), NULL, NULL},
- { "max_round_trips", PW_TYPE_INTEGER,
- offsetof(rlm_securid_t, max_trips_per_session), NULL, "6"},
+ { "timer_expire", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_securid_t, timer_limit), "600" },
+ { "max_sessions", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_securid_t, max_sessions), "2048" },
+ { "max_trips_per_session", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_securid_t, max_trips_per_session), NULL },
+ { "max_round_trips", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_securid_t, max_trips_per_session), "6" },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
securid_session->identity = strdup(username);
/* Get PIN requirements */
- acm_ret = AceGetPinParams(sdiHandle, &pin_params);
+ (void) AceGetPinParams(sdiHandle, &pin_params);
/* If a system-generated PIN is required */
if (pin_params.Selectable == CANNOT_CHOOSE_PIN) {
*/
inst->session_tree = rbtree_create(securid_session_cmp, NULL, 0);
if (!inst->session_tree) {
- ERROR("rlm_securid: Cannot initialize session tree.");
+ ERROR("rlm_securid: Cannot initialize session tree");
return -1;
}
/*
* Authenticate the user via one of any well-known password.
*/
-static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
{
int rcode;
rlm_securid_t *inst = instance;
* a User-Name attribute.
*/
if (!request->username) {
- AUTH("rlm_securid: Attribute \"User-Name\" is required for authentication.");
+ AUTH("rlm_securid: Attribute \"User-Name\" is required for authentication");
return RLM_MODULE_INVALID;
}
if (!request->password) {
- RAUTH("Attribute \"Password\" is required for authentication.");
+ RAUTH("Attribute \"Password\" is required for authentication");
return RLM_MODULE_INVALID;
}
username = request->username->vp_strvalue;
password = request->password->vp_strvalue;
- RDEBUG("User [%s] login attempt with password [%s]",
- username, password);
+ if (RDEBUG_ENABLED3) {
+ RDEBUG3("Login attempt with password \"%s\"", password);
+ } else {
+ RDEBUG("Login attempt with password");
+ }
rcode = securidAuth(inst, request, username, password,
buffer, sizeof(buffer));
pairadd(&request->reply->vps, vp);
/* Mark the packet as a Acceess-Challenge Packet */
- request->reply->code = PW_ACCESS_CHALLENGE;
- RDEBUG("Sending Access-Challenge.");
+ request->reply->code = PW_CODE_ACCESS_CHALLENGE;
+ RDEBUG("Sending Access-Challenge");
rcode = RLM_MODULE_HANDLED;
break;
module_t rlm_securid = {
RLM_MODULE_INIT,
"securid",
- RLM_TYPE_CHECK_CONFIG_SAFE | RLM_TYPE_HUP_SAFE, /* type */
+ RLM_TYPE_HUP_SAFE, /* type */
sizeof(rlm_securid_t),
module_config,
mod_instantiate, /* instantiation */
fr_ipaddr_t src_ipaddr;
time_t timestamp;
unsigned int session_id;
- int trips;
+ uint32_t trips;
char *pin; /* previous pin if user entered it during NEW-PIN mode process */
char *identity; /* save user's identity name for future use */
/*
* Configuration items.
*/
- int timer_limit;
- int max_sessions;
- int max_trips_per_session;
+ uint32_t timer_limit;
+ uint32_t max_sessions;
+ uint32_t max_trips_per_session;
} rlm_securid_t;
/* Memory Management */
SECURID_SESSION* securid_session_alloc(void);
-void securid_session_free(rlm_securid_t *inst, REQUEST *request,SECURID_SESSION *session);
+void securid_session_free(rlm_securid_t *inst, REQUEST *request,SECURID_SESSION *session)
+ CC_HINT(nonnull);
-void securid_sessionlist_free(rlm_securid_t *inst,REQUEST *request);
+void securid_sessionlist_free(rlm_securid_t *inst,REQUEST *request) CC_HINT(nonnull);
-int securid_sessionlist_add(rlm_securid_t *inst, REQUEST *request, SECURID_SESSION *session);
-SECURID_SESSION* securid_sessionlist_find(rlm_securid_t *inst, REQUEST *request);
+int securid_sessionlist_add(rlm_securid_t *inst, REQUEST *request, SECURID_SESSION *session)
+ CC_HINT(nonnull);
+SECURID_SESSION *securid_sessionlist_find(rlm_securid_t *inst, REQUEST *request) CC_HINT(nonnull);
#endif
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
CPP C preprocessor
Use these variables to override the choices made by `configure' or to help
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
--header=FILE[:TEMPLATE]
- instantiate the configuration header FILE
+ instantiate the configuration header FILE
Configuration files:
$config_files
#include <sys/un.h>
typedef struct rlm_smsotp_t {
- char *socket;
- char *challenge;
- char *authtype;
+ char const *socket;
+ char const *challenge;
+ char const *authtype;
fr_connection_pool_t *pool;
} rlm_smsotp_t;
static const CONF_PARSER module_config[] = {
- { "socket", PW_TYPE_STRING_PTR,
- offsetof(rlm_smsotp_t, socket),
- NULL, "/var/run/smsotp_socket" },
- { "challenge_message", PW_TYPE_STRING_PTR,
- offsetof(rlm_smsotp_t, challenge), NULL, "Enter Mobile PIN" },
- { "challenge_type", PW_TYPE_STRING_PTR,
- offsetof(rlm_smsotp_t, authtype),
- NULL, "smsotp-reply" },
+ { "socket", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_smsotp_t, socket), "/var/run/smsotp_socket" },
+ { "challenge_message", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_smsotp_t, challenge), "Enter Mobile PIN" },
+ { "challenge_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_smsotp_t, authtype), "smsotp-reply" },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
ERROR("Failed opening SMSOTP file %s: %s",
- inst->socket, strerror(errno));
+ inst->socket, fr_syserror(errno));
return NULL;
}
if (connect(fd, (struct sockaddr *) &sa, socklen) < -1) {
ERROR("Failed connecting to SMSOTP file %s: %s",
- inst->socket, strerror(errno));
+ inst->socket, fr_syserror(errno));
return NULL;
}
/*
* Authenticate the user with the given password.
*/
-static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
{
rlm_smsotp_t *inst = instance;
VALUE_PAIR *state;
char output[1000];
fdp = fr_connection_get(inst->pool);
- if (!fdp) {
- REDEBUG("Failed to get handle from connection pool");
- return RLM_MODULE_FAIL;
- }
+ if (!fdp) return RLM_MODULE_FAIL;
/* Get greeting */
bufsize = read_all(fdp, buffer, sizeof(buffer));
*/
#define WRITE_ALL(_a,_b,_c) if (write_all(_a,_b,_c) < 0) goto done;
state = pairfind(request->packet->vps, PW_STATE, 0, TAG_ANY);
- if (!state) {
+ if (state) {
RDEBUG("Found reply to access challenge");
/* send username */
request->username->vp_strvalue);
WRITE_ALL(fdp, output, strlen(output));
- bufsize = read_all(fdp, buffer, sizeof(buffer));
+ (void) read_all(fdp, buffer, sizeof(buffer));
/* send password */
snprintf(output, sizeof(output), "user otp is %s\n",
request->password->vp_strvalue);
WRITE_ALL(fdp, output, strlen(output));
- bufsize = read_all(fdp, buffer, sizeof(buffer));
+ (void) read_all(fdp, buffer, sizeof(buffer));
/* set uuid */
snprintf(output, sizeof(output), "otp id is %s\n",
state->vp_strvalue);
WRITE_ALL(fdp, output, strlen(output));
- bufsize = read_all(fdp, buffer, sizeof(buffer));
+ (void) read_all(fdp, buffer, sizeof(buffer));
/* now check the otp */
WRITE_ALL(fdp, "get check result\n", 17);
- bufsize = read_all(fdp, buffer, sizeof(buffer));
+ (void) read_all(fdp, buffer, sizeof(buffer));
/* end the sesssion */
WRITE_ALL(fdp, "quit\n", 5);
request->username->vp_strvalue);
WRITE_ALL(fdp, output, strlen(output));
- bufsize = read_all(fdp, buffer, sizeof(buffer));
+ (void) read_all(fdp, buffer, sizeof(buffer));
/* end the sesssion */
WRITE_ALL(fdp, "quit\n", 5);
*
* The server will take care of sending it to the user.
*/
- request->reply->code = PW_ACCESS_CHALLENGE;
- DEBUG("rlm_smsotp: Sending Access-Challenge.");
+ request->reply->code = PW_CODE_ACCESS_CHALLENGE;
+ DEBUG("rlm_smsotp: Sending Access-Challenge");
rcode = RLM_MODULE_HANDLED;
* from the database. The authentication code only needs to check
* the password, the rest is done here.
*/
-static rlm_rcode_t mod_authorize(UNUSED void *instance, UNUSED REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, UNUSED REQUEST *request)
{
VALUE_PAIR *state;
rlm_smsotp_t *inst = instance;
/*
* Do SoH over DHCP?
*/
- { "dhcp", PW_TYPE_BOOLEAN, offsetof(rlm_soh_t,dhcp), NULL, "no" },
+ { "dhcp", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_soh_t, dhcp), "no" },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
return 0;
}
-static rlm_rcode_t mod_post_auth(UNUSED void * instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(UNUSED void * instance, UNUSED REQUEST *request)
{
#ifdef WITH_DHCP
int rcode;
VALUE_PAIR *vp;
+ rlm_soh_t *inst = instance;
+
+ if (!inst->dhcp) return RLM_MODULE_NOOP;
vp = pairfind(request->packet->vps, 43, DHCP_MAGIC_VENDOR, TAG_ANY);
if (vp) {
return RLM_MODULE_NOOP;
}
-static rlm_rcode_t mod_authorize(UNUSED void * instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void * instance, REQUEST *request)
{
VALUE_PAIR *vp;
int rv;
* going to return.
*/
typedef struct rlm_sometimes_t {
- char *rcode_str;
- int rcode;
- int start;
- int end;
- char *key;
- DICT_ATTR const *da;
+ char const *rcode_str;
+ rlm_rcode_t rcode;
+ uint32_t start;
+ uint32_t end;
+ char const *key;
+ DICT_ATTR const *da;
} rlm_sometimes_t;
/*
* buffer over-flows.
*/
static const CONF_PARSER module_config[] = {
- { "rcode", PW_TYPE_STRING_PTR, offsetof(rlm_sometimes_t,rcode_str), NULL, "fail" },
- { "key", PW_TYPE_STRING_PTR | PW_TYPE_ATTRIBUTE, offsetof(rlm_sometimes_t,key), NULL, "User-Name" },
- { "start", PW_TYPE_INTEGER, offsetof(rlm_sometimes_t,start), NULL, "0" },
- { "end", PW_TYPE_INTEGER, offsetof(rlm_sometimes_t,end), NULL, "127" },
+ { "rcode", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sometimes_t, rcode_str), "fail" },
+ { "key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_ATTRIBUTE, rlm_sometimes_t, key), "User-Name" },
+ { "start", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_sometimes_t, start), "0" },
+ { "end", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_sometimes_t, end), "127" },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
/*
* Convert the rcode string to an int, and get rid of it
*/
- inst->rcode = fr_str2int(mod_rcode_table, inst->rcode_str, -1);
- if (inst->rcode == -1) {
+ inst->rcode = fr_str2int(mod_rcode_table, inst->rcode_str, RLM_MODULE_UNKNOWN);
+ if (inst->rcode == RLM_MODULE_UNKNOWN) {
cf_log_err_cs(conf, "Unknown module return code '%s'", inst->rcode_str);
return -1;
}
/*
* A lie! It always returns!
*/
-static rlm_rcode_t sometimes_return(void *instance, RADIUS_PACKET *packet,
- RADIUS_PACKET *reply)
+static rlm_rcode_t sometimes_return(void *instance, RADIUS_PACKET *packet, RADIUS_PACKET *reply)
{
uint32_t hash;
- int value;
+ uint32_t value;
rlm_sometimes_t *inst = instance;
VALUE_PAIR *vp;
*/
if ((inst->rcode == RLM_MODULE_HANDLED) && reply) {
switch (packet->code) {
- case PW_AUTHENTICATION_REQUEST:
- reply->code = PW_AUTHENTICATION_ACK;
+ case PW_CODE_AUTHENTICATION_REQUEST:
+ reply->code = PW_CODE_AUTHENTICATION_ACK;
break;
- case PW_ACCOUNTING_REQUEST:
- reply->code = PW_ACCOUNTING_RESPONSE;
+ case PW_CODE_ACCOUNTING_REQUEST:
+ reply->code = PW_CODE_ACCOUNTING_RESPONSE;
break;
- case PW_COA_REQUEST:
- reply->code = PW_COA_ACK;
+ case PW_CODE_COA_REQUEST:
+ reply->code = PW_CODE_COA_ACK;
break;
- case PW_DISCONNECT_REQUEST:
- reply->code = PW_DISCONNECT_ACK;
+ case PW_CODE_DISCONNECT_REQUEST:
+ reply->code = PW_CODE_DISCONNECT_ACK;
break;
default:
return inst->rcode;
}
-static rlm_rcode_t sometimes_packet(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_sometimes_packet(void *instance, REQUEST *request)
{
return sometimes_return(instance, request->packet, request->reply);
}
-static rlm_rcode_t sometimes_reply(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_sometimes_reply(void *instance, REQUEST *request)
{
return sometimes_return(instance, request->reply, NULL);
}
#ifdef WITH_PROXY
-static rlm_rcode_t mod_pre_proxy(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_pre_proxy(void *instance, REQUEST *request)
{
if (!request->proxy) return RLM_MODULE_NOOP;
return sometimes_return(instance, request->proxy, request->proxy_reply);
}
-static rlm_rcode_t mod_post_proxy(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_post_proxy(void *instance, REQUEST *request)
{
if (!request->proxy_reply) return RLM_MODULE_NOOP;
module_t rlm_sometimes = {
RLM_MODULE_INIT,
"sometimes",
- RLM_TYPE_CHECK_CONFIG_SAFE | RLM_TYPE_HUP_SAFE, /* type */
+ RLM_TYPE_HUP_SAFE, /* type */
sizeof(rlm_sometimes_t),
module_config,
mod_instantiate, /* instantiation */
NULL, /* detach */
{
- sometimes_packet, /* authentication */
- sometimes_packet, /* authorization */
- sometimes_packet, /* preaccounting */
- sometimes_packet, /* accounting */
+ mod_sometimes_packet, /* authentication */
+ mod_sometimes_packet, /* authorization */
+ mod_sometimes_packet, /* preaccounting */
+ mod_sometimes_packet, /* accounting */
NULL,
#ifdef WITH_PROXY
- mod_pre_proxy, /* pre-proxy */
- mod_post_proxy, /* post-proxy */
+ mod_pre_proxy, /* pre-proxy */
+ mod_post_proxy, /* post-proxy */
#else
NULL, NULL,
#endif
- sometimes_reply /* post-auth */
+ mod_sometimes_reply /* post-auth */
#ifdef WITH_COA
,
- sometimes_packet, /* recv-coa */
- sometimes_reply /* send-coa */
+ mod_sometimes_packet, /* recv-coa */
+ mod_sometimes_reply /* send-coa */
#endif
},
};
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-ibmdb2-include-dir=DIR
- Directory where the IBM-DB2 includes may be found
+ Directory where the IBM-DB2 includes may be found
--with-ibmdb2-lib-dir=DIR
- Directory where the IBM-DB2 libraries may be found
+ Directory where the IBM-DB2 libraries may be found
--with-ibmdb2-dir=DIR Base directory where IBM-DB2 is installed
Some influential environment variables:
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-ldb2"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-ldb2"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libdb2${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libdb2.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=sqlcli.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
TALLOC_FREE(conn->error);
SQLGetDiagRec(SQL_HANDLE_STMT, conn->stmt, 1, (SQLCHAR *) sqlstate, &err, (SQLCHAR *) msg, sizeof(msg), &rl);
- conn->error = talloc_asprintf(conn, "sqlstate %s: %s", sqlstate, msg);
+ conn->error = talloc_typed_asprintf(conn, "sqlstate %s: %s", sqlstate, msg);
return conn->error;
}
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-firebird-include-dir=DIR
- Directory where the firebird includes may be found
+ Directory where the firebird includes may be found
--with-firebird-lib-dir=DIR
- Directory where the firebird libraries may be found
+ Directory where the firebird libraries may be found
--with-firebird-dir=DIR Base directory where firebird is installed
Some influential environment variables:
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lfbclient"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lfbclient"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libfbclient${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libfbclient.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=ibase.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
isc_detach_database(conn->status, &(conn->dbh));
if (fb_error(conn)) {
- WDEBUG("rlm_sql_firebird: Got error "
+ WARN("rlm_sql_firebird: Got error "
"when closing socket: %s", conn->error);
}
}
* Try again query when deadlock, beacuse in any case it
* will be retried.
*/
- if (fb_sql_query(conn, query)) {
+ if (fb_sql_query(conn, query)) {
/* but may be lost for short sessions */
- if ((conn->sql_code == DEADLOCK_SQL_CODE) &&
- !deadlock) {
- DEBUG("conn_id deadlock. Retry query %s", query);
+ if ((conn->sql_code == DEADLOCK_SQL_CODE) &&
+ !deadlock) {
+ DEBUG("conn_id deadlock. Retry query %s", query);
/*
* @todo For non READ_COMMITED transactions put
* rollback here
* fb_rollback(conn);
*/
- deadlock = 1;
- goto try_again;
- }
+ deadlock = 1;
+ goto try_again;
+ }
ERROR("conn_id rlm_sql_firebird,sql_query error: sql_code=%li, error='%s', query=%s",
(long int) conn->sql_code, conn->error, query);
if (conn->sql_code == DOWN_SQL_CODE) {
+ reconnect:
#ifdef _PTHREAD_H
- pthread_mutex_lock(&conn->mut);
+ pthread_mutex_unlock(&conn->mut);
#endif
-
return RLM_SQL_RECONNECT;
}
//assume the network is down if rollback had failed
ERROR("Fail to rollback transaction after previous error: %s", conn->error);
- return RLM_SQL_RECONNECT;
+ goto reconnect;
}
// conn->in_use=0;
+ fail:
+#ifdef _PTHREAD_H
+ pthread_mutex_unlock(&conn->mut);
+#endif
return -1;
- }
+ }
if (conn->statement_type != isc_info_sql_stmt_select) {
- if (fb_commit(conn)) {
- return -1;
- }
+ if (fb_commit(conn)) goto fail;
}
+#ifdef _PTHREAD_H
+ pthread_mutex_unlock(&conn->mut);
+#endif
return 0;
}
res = fb_fetch(conn);
if (res == 100) {
return 0;
- }
+ }
- if (res) {
- ERROR("rlm_sql_firebird. Fetch problem: %s", conn->error);
+ if (res) {
+ ERROR("rlm_sql_firebird. Fetch problem: %s", conn->error);
- return -1;
- }
+ return -1;
+ }
} else {
conn->statement_type=0;
}
* API.
*/
isc_interprete(&error[0], &pstatus);
- conn->error = talloc_asprintf(conn, "%s. ", &error[0]);
+ conn->error = talloc_typed_asprintf(conn, "%s. ", &error[0]);
while (isc_interprete(&error[0], &pstatus)) {
conn->error = talloc_asprintf_append(conn->error, "%s. ", &error[0]);
conn->row_sizes[i] = vary->vary_length + 1;
conn->row[i] = realloc(conn->row[i],
conn->row_sizes[i]);
- }
+ }
memmove(conn->row[i], vary->vary_string, vary->vary_length);
conn->row[i][vary->vary_length] = 0;
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-freetds-include-dir=DIR
- Directory where the freetds includes may be found
+ Directory where the freetds includes may be found
--with-freetds-lib-dir=DIR
- Directory where the freetds libraries may be found
+ Directory where the freetds libraries may be found
--with-freetds-dir=DIR Base directory where freetds is installed
Some influential environment variables:
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
if test x$with_rlm_sql_freetds != xno; then
- freetds_include_dir=
+ freetds_include_dir=
# Check whether --with-freetds-include-dir was given.
if test "${with_freetds_include_dir+set}" = set; then :
fi
- freetds_lib_dir=
+ freetds_lib_dir=
# Check whether --with-freetds-lib-dir was given.
if test "${with_freetds_lib_dir+set}" = set; then :
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=ctpublic.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
fi
- smart_try_dir="$freetds_lib_dir"
+ smart_try_dir="$freetds_lib_dir"
sm_lib_safe=`echo "ct" | sed 'y%./+-%__p_%'`
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lct"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lct"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libct${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libct.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
if (this->error) TALLOC_FREE(this->error);
- this->error = talloc_asprintf(this, "client error: severity(%ld), number(%ld), origin(%ld), layer(%ld): %s",
+ this->error = talloc_typed_asprintf(this, "client error: severity(%ld), number(%ld), origin(%ld), layer(%ld): %s",
(long)CS_SEVERITY(emsgp->severity), (long)CS_NUMBER(emsgp->msgnumber),
(long)CS_ORIGIN(emsgp->msgnumber), (long)CS_LAYER(emsgp->msgnumber),
emsgp->msgstring);
if (this->error) TALLOC_FREE(this->error);
- this->error = talloc_asprintf(this, "cs error: severity(%ld), number(%ld), origin(%ld), layer(%ld): %s",
+ this->error = talloc_typed_asprintf(this, "cs error: severity(%ld), number(%ld), origin(%ld), layer(%ld): %s",
(long)CS_SEVERITY(emsgp->severity), (long)CS_NUMBER(emsgp->msgnumber),
(long)CS_ORIGIN(emsgp->msgnumber), (long)CS_LAYER(emsgp->msgnumber),
emsgp->msgstring);
} else {
if (this->error) TALLOC_FREE(this->error);
- this->error = talloc_asprintf(this, "server msg from \"%s\": severity(%ld), number(%ld), origin(%ld), "
- "layer(%ld), procedure \"%s\": %s",
- (msgp->svrnlen > 0) ? msgp->svrname : "unknown",
- (long)msgp->msgnumber, (long)msgp->severity, (long)msgp->state,
- (long)msgp->line,
- (msgp->proclen > 0) ? msgp->proc : "none", msgp->text);
+ this->error = talloc_typed_asprintf(this, "server msg from \"%s\": severity(%ld), number(%ld), origin(%ld), "
+ "layer(%ld), procedure \"%s\": %s",
+ (msgp->svrnlen > 0) ? msgp->svrname : "unknown",
+ (long)msgp->msgnumber, (long)msgp->severity, (long)msgp->state,
+ (long)msgp->line,
+ (msgp->proclen > 0) ? msgp->proc : "none", msgp->text);
}
return CS_SUCCEED;
case CS_FAIL: /* Serious failure, freetds requires us to cancel and maybe even close db */
ERROR("rlm_sql_freetds: failure retrieving query results");
if ((ret = ct_cancel(NULL, conn->command, CS_CANCEL_ALL)) == CS_FAIL) {
- INFO("rlm_sql_freetds: cleaning up.");
+ INFO("rlm_sql_freetds: cleaning up");
return RLM_SQL_RECONNECT;
}
ERROR("rlm_sql_freetds: failure retrieving query results");
if ((ret = ct_cancel(NULL, conn->command, CS_CANCEL_ALL)) == CS_FAIL) {
- ERROR("rlm_sql_freetds: cleaning up.");
+ ERROR("rlm_sql_freetds: cleaning up");
return RLM_SQL_RECONNECT;
}
*/
ERROR("rlm_sql_freetds: failure fetching row data");
if ((ret = ct_cancel(NULL, conn->command, CS_CANCEL_ALL)) == CS_FAIL) {
- ERROR("rlm_sql_freetds: cleaning up.");
+ ERROR("rlm_sql_freetds: cleaning up");
} else {
conn->command = NULL;
}
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-iodbc-include-dir=DIR
- Directory where the Iodbc includes may be found
+ Directory where the Iodbc includes may be found
--with-iodbc-lib-dir=DIR
- Directory where the Iodbc libraries may be found
+ Directory where the Iodbc libraries may be found
--with-iodbc-dir=DIR Base directory where Iodbc is installed
Some influential environment variables:
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-liodbc"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-liodbc"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libiodbc${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libiodbc.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=isql.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-mysql-include-dir=DIR
- Directory where the mysql includes may be found
+ Directory where the mysql includes may be found
--with-mysql-lib-dir=DIR
- Directory where the mysql libraries may be found
+ Directory where the mysql libraries may be found
--with-mysql-dir=DIR Base directory where mysql is installed
--with-threads use threads, if available. (default=yes)
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
if test x$with_rlm_sql_mysql != xno; then
- mysql_include_dir=
+ mysql_include_dir=
# Check whether --with-mysql-include-dir was given.
if test "${with_mysql_include_dir+set}" = set; then :
fi
- mysql_lib_dir=
+ mysql_lib_dir=
# Check whether --with-mysql-lib-dir was given.
if test "${with_mysql_lib_dir+set}" = set; then :
fi
- mysql_with_threads=yes
+ mysql_with_threads=yes
# Check whether --with-threads was given.
if test "${with_threads+set}" = set; then :
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
- if test "x$mysql_with_threads" = "xyes"; then
+ if test "x$mysql_with_threads" = "xyes"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
$as_echo_n "checking for pthread_create in -lpthread... " >&6; }
fi
fi
if test "x$have_libmysqlclient_r" != "xyes"; then
- smart_try_dir="$mysql_lib_dir /usr/lib /usr/lib/mysql \
+ smart_try_dir="$mysql_lib_dir /usr/lib /usr/lib/mysql \
/usr/local/lib/mysql /usr/local/mysql/lib/mysql"
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lmysqlclient_r"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lmysqlclient_r"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libmysqlclient_r${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libmysqlclient_r.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
fi
fi
if test "x$have_libmysqlclient" != "xyes"; then
- smart_try_dir="$mysql_lib_dir /usr/lib /usr/lib/mysql \
+ smart_try_dir="$mysql_lib_dir /usr/lib /usr/lib/mysql \
/usr/local/lib/mysql /usr/local/mysql/lib/mysql"
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lmysqlclient"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lmysqlclient"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libmysqlclient${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libmysqlclient.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
if test "x$have_mysql_h" = "xyes"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
$as_echo "#define HAVE_MYSQL_H /**/" >>confdefs.h
- SMART_CFLAGS="$SMART_CFLAGS $mod_cflags"
+ SMART_CFLAGS="$SMART_CFLAGS $mod_cflags"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
- fi
+ fi
CFLAGS="$old_CFLAGS"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=mysql/mysql.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
$as_echo "#define HAVE_MYSQL_MYSQL_H /**/" >>confdefs.h
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: MySQL headers not found. Use --with-mysql-include-dir=<path>." >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: MySQL headers not found. Use --with-mysql-include-dir=<path>." >&5
$as_echo "$as_me: WARNING: MySQL headers not found. Use --with-mysql-include-dir=<path>." >&2;}
fail="$fail mysql.h"
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
--header=FILE[:TEMPLATE]
- instantiate the configuration header FILE
+ instantiate the configuration header FILE
Configuration files:
$config_files
CFLAGS="$old_CFLAGS $mod_cflags"
AC_MSG_CHECKING([for mysql.h (using mysql_config --include)])
AC_TRY_COMPILE([#include <mysql.h>], [int a = 1;],
- have_mysql_h=yes)
+ have_mysql_h=yes)
if test "x$have_mysql_h" = "xyes"; then
- AC_MSG_RESULT(yes)
- AC_DEFINE(HAVE_MYSQL_H, [], [Define if you have <mysql.h>])
- SMART_CFLAGS="$SMART_CFLAGS $mod_cflags"
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_MYSQL_H, [], [Define if you have <mysql.h>])
+ SMART_CFLAGS="$SMART_CFLAGS $mod_cflags"
else
- AC_MSG_RESULT(no)
+ AC_MSG_RESULT(no)
fi
- fi
+ fi
CFLAGS="$old_CFLAGS"
fi
#include "config.h"
#ifdef HAVE_MYSQL_MYSQL_H
-#include <mysql/mysql_version.h>
-#include <mysql/errmsg.h>
-#include <mysql/mysql.h>
-#else
-#ifdef HAVE_MYSQL_H
-#include <mysql_version.h>
-#include <errmsg.h>
-#include <mysql.h>
-#endif
+# include <mysql/mysql_version.h>
+# include <mysql/errmsg.h>
+# include <mysql/mysql.h>
+#elif defined(HAVE_MYSQL_H)
+# include <mysql_version.h>
+# include <errmsg.h>
+# include <mysql.h>
#endif
#include "rlm_sql.h"
+static int mysql_instance_count = 0;
+
typedef struct rlm_sql_mysql_conn {
- MYSQL db;
- MYSQL *sock;
- MYSQL_RES *result;
- rlm_sql_row_t row;
+ MYSQL db;
+ MYSQL *sock;
+ MYSQL_RES *result;
+ rlm_sql_row_t row;
} rlm_sql_mysql_conn_t;
typedef struct rlm_sql_mysql_config {
- char const *tls_ca_file;
- char const *tls_ca_path;
- char const *tls_certificate_file;
- char const *tls_private_key_file;
- char const *tls_cipher;
+ char const *tls_ca_file;
+ char const *tls_ca_path;
+ char const *tls_certificate_file;
+ char const *tls_private_key_file;
+ char const *tls_cipher;
} rlm_sql_mysql_config_t;
static CONF_PARSER tls_config[] = {
- {"ca_file", PW_TYPE_FILE_INPUT, offsetof(rlm_sql_mysql_config_t, tls_ca_file), NULL, NULL},
- {"ca_path", PW_TYPE_FILE_INPUT, offsetof(rlm_sql_mysql_config_t, tls_ca_path), NULL, NULL},
- {"certificate_file", PW_TYPE_FILE_INPUT, offsetof(rlm_sql_mysql_config_t, tls_certificate_file), NULL, NULL},
- {"private_key_file", PW_TYPE_FILE_INPUT, offsetof(rlm_sql_mysql_config_t, tls_private_key_file), NULL, NULL},
+ { "ca_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_sql_mysql_config_t, tls_ca_file), NULL },
+ { "ca_path", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_sql_mysql_config_t, tls_ca_path), NULL },
+ { "certificate_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_sql_mysql_config_t, tls_certificate_file), NULL },
+ { "private_key_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_sql_mysql_config_t, tls_private_key_file), NULL },
/*
* MySQL Specific TLS attributes
*/
- {"cipher", PW_TYPE_STRING_PTR, offsetof(rlm_sql_mysql_config_t, tls_cipher), NULL, NULL},
+ { "cipher", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_mysql_config_t, tls_cipher), NULL },
{ NULL, -1, 0, NULL, NULL }
};
static const CONF_PARSER driver_config[] = {
- { "tls", PW_TYPE_SUBSECTION, 0, NULL, (void const *) tls_config },
+ { "tls", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) tls_config },
{NULL, -1, 0, NULL, NULL}
};
return 0;
}
+static int _mod_destructor(UNUSED rlm_sql_mysql_config_t *driver)
+{
+ mysql_instance_count--;
+
+ if (mysql_instance_count == 0) {
+ mysql_library_end();
+ }
+
+ return 0;
+}
+
static int mod_instantiate(CONF_SECTION *conf, rlm_sql_config_t *config)
{
rlm_sql_mysql_config_t *driver;
+ if (mysql_instance_count == 0) {
+ if (mysql_library_init(0, NULL, NULL)) {
+ ERROR("Could not initialise MySQL library");
+
+ return -1;
+ }
+ }
+ mysql_instance_count++;
+
MEM(driver = config->driver = talloc_zero(config, rlm_sql_mysql_config_t));
+ talloc_set_destructor(driver, _mod_destructor);
if (cf_section_parse(conf, driver, driver_config) < 0) {
return -1;
*/
if (timeout > 3) timeout /= 3;
- mysql_options(&(conn->db), MYSQL_OPT_CONNECT_TIMEOUT,
- &timeout);
- mysql_options(&(conn->db), MYSQL_OPT_READ_TIMEOUT,
- &timeout);
- mysql_options(&(conn->db), MYSQL_OPT_WRITE_TIMEOUT,
- &timeout);
+ mysql_options(&(conn->db), MYSQL_OPT_CONNECT_TIMEOUT, &timeout);
+ mysql_options(&(conn->db), MYSQL_OPT_READ_TIMEOUT, &timeout);
+ mysql_options(&(conn->db), MYSQL_OPT_WRITE_TIMEOUT, &timeout);
}
#endif
NULL,
sql_flags);
if (!conn->sock) {
- ERROR("rlm_sql_mysql: Couldn't connect socket to MySQL "
- "server %s@%s:%s", config->sql_login, config->sql_server,
- config->sql_db);
- ERROR("rlm_sql_mysql: Mysql error '%s'",
- mysql_error(&conn->db));
+ ERROR("rlm_sql_mysql: Couldn't connect socket to MySQL server %s@%s:%s", config->sql_login,
+ config->sql_server, config->sql_db);
+ ERROR("rlm_sql_mysql: Mysql error '%s'", mysql_error(&conn->db));
conn->sock = NULL;
-
- return -1;
+ return RLM_SQL_ERROR;
}
-
- return 0;
+ return RLM_SQL_OK;
}
/*************************************************************************
* Purpose: check the error to see if the server is down
*
*************************************************************************/
-static int sql_check_error(int error)
+static sql_rcode_t sql_check_error(int error)
{
switch(error) {
+ case 0:
+ return RLM_SQL_OK;
+
case CR_SERVER_GONE_ERROR:
case CR_SERVER_LOST:
case -1:
DEBUG("rlm_sql_mysql: MYSQL check_error: %d, returning RLM_SQL_RECONNECT", error);
return RLM_SQL_RECONNECT;
- break;
- case 0:
- return 0;
- break;
+
case CR_OUT_OF_MEMORY:
case CR_COMMANDS_OUT_OF_SYNC:
case CR_UNKNOWN_ERROR:
default:
DEBUG("rlm_sql_mysql: MYSQL check_error: %d received", error);
- return -1;
- break;
+ return RLM_SQL_ERROR;
}
}
static sql_rcode_t sql_query(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config, char const *query)
{
rlm_sql_mysql_conn_t *conn = handle->conn;
+ sql_rcode_t rcode;
+ char const *info;
if (!conn->sock) {
ERROR("rlm_sql_mysql: Socket not connected");
}
mysql_query(conn->sock, query);
- return sql_check_error(mysql_errno(conn->sock));
+ rcode = sql_check_error(mysql_errno(conn->sock));
+ if (rcode != RLM_SQL_OK) {
+ return rcode;
+ }
+
+ /* Only returns non-null string for INSERTS */
+ info = mysql_info(conn->sock);
+ if (info) DEBUG2("rlm_sql_mysql: %s", info);
+
+ return RLM_SQL_OK;
}
static sql_rcode_t sql_store_result(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
{
rlm_sql_mysql_conn_t *conn = handle->conn;
- int status;
+ sql_rcode_t rcode;
+ int ret;
if (!conn->sock) {
ERROR("rlm_sql_mysql: Socket not connected");
return RLM_SQL_RECONNECT;
}
+
retry_store_result:
if (!(conn->result = mysql_store_result(conn->sock))) {
- status = sql_check_error(mysql_errno(conn->sock));
- if (status != 0) {
+ rcode = sql_check_error(mysql_errno(conn->sock));
+ if (rcode != RLM_SQL_OK) {
ERROR("rlm_sql_mysql: Cannot store result");
- ERROR("rlm_sql_mysql: MySQL error '%s'",
- mysql_error(conn->sock));
- return status;
+ ERROR("rlm_sql_mysql: MySQL error '%s'", mysql_error(conn->sock));
+
+ return rcode;
}
#if (MYSQL_VERSION_ID >= 40100)
- status = mysql_next_result(conn->sock);
- if (status == 0) {
+ ret = mysql_next_result(conn->sock);
+ if (ret == 0) {
/* there are more results */
goto retry_store_result;
- } else if (status > 0) {
+ } else if (ret > 0) {
ERROR("rlm_sql_mysql: Cannot get next result");
- ERROR("rlm_sql_mysql: MySQL error '%s'",
- mysql_error(conn->sock));
- return sql_check_error(status);
+ ERROR("rlm_sql_mysql: MySQL error '%s'", mysql_error(conn->sock));
+
+ return sql_check_error(ret);
}
#endif
}
- return 0;
+ return RLM_SQL_OK;
}
* of columns from query
*
*************************************************************************/
-static int sql_num_fields(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
+static int sql_num_fields(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
{
- int num = 0;
+ int num = 0;
rlm_sql_mysql_conn_t *conn = handle->conn;
#if MYSQL_VERSION_ID >= 32224
if (!(num = mysql_num_fields(conn->sock))) {
#endif
ERROR("rlm_sql_mysql: MYSQL Error: No Fields");
- ERROR("rlm_sql_mysql: MYSQL error: %s",
- mysql_error(conn->sock));
+ ERROR("rlm_sql_mysql: MYSQL error: %s", mysql_error(conn->sock));
}
return num;
}
*************************************************************************/
static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query)
{
- int ret;
+ sql_rcode_t rcode;
- ret = sql_query(handle, config, query);
- if(ret)
- return ret;
- ret = sql_store_result(handle, config);
- if (ret) {
- return ret;
+ rcode = sql_query(handle, config, query);
+ if (rcode != RLM_SQL_OK) {
+ return rcode;
+ }
+
+ rcode = sql_store_result(handle, config);
+ if (rcode != RLM_SQL_OK) {
+ return rcode;
}
/* Why? Per http://www.mysql.com/doc/n/o/node_591.html,
*/
sql_num_fields(handle, config);
- return ret;
+ return rcode;
}
{
rlm_sql_mysql_conn_t *conn = handle->conn;
- if (conn->result)
+ if (conn->result) {
return mysql_num_rows(conn->result);
+ }
return 0;
}
static sql_rcode_t sql_fetch_row(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
{
rlm_sql_mysql_conn_t *conn = handle->conn;
- int status;
+ sql_rcode_t rcode;
+ int ret;
/*
* Check pointer before de-referencing it.
retry_fetch_row:
handle->row = mysql_fetch_row(conn->result);
-
if (!handle->row) {
- status = sql_check_error(mysql_errno(conn->sock));
- if (status != 0) {
+ rcode = sql_check_error(mysql_errno(conn->sock));
+ if (rcode != RLM_SQL_OK) {
ERROR("rlm_sql_mysql: Cannot fetch row");
- ERROR("rlm_sql_mysql: MySQL error '%s'",
- mysql_error(conn->sock));
- return status;
+ ERROR("rlm_sql_mysql: MySQL error '%s'", mysql_error(conn->sock));
+
+ return rcode;
}
+
#if (MYSQL_VERSION_ID >= 40100)
sql_free_result(handle, config);
- status = mysql_next_result(conn->sock);
- if (status == 0) {
+
+ ret = mysql_next_result(conn->sock);
+ if (ret == 0) {
/* there are more results */
- if ((sql_store_result(handle, config) == 0)
- && (conn->result != NULL))
+ if ((sql_store_result(handle, config) == 0) && (conn->result != NULL)) {
goto retry_fetch_row;
- } else if (status > 0) {
+ }
+ } else if (ret > 0) {
ERROR("rlm_sql_mysql: Cannot get next result");
- ERROR("rlm_sql_mysql: MySQL error '%s'",
- mysql_error(conn->sock));
- return sql_check_error(status);
+ ERROR("rlm_sql_mysql: MySQL error '%s'", mysql_error(conn->sock));
+
+ return sql_check_error(ret);
}
#endif
}
- return 0;
+ return RLM_SQL_OK;
}
if (!conn || !conn->sock) {
return "rlm_sql_mysql: no connection to db";
}
+
return mysql_error(conn->sock);
}
{
#if (MYSQL_VERSION_ID >= 40100)
rlm_sql_mysql_conn_t *conn = handle->conn;
- int status;
+ sql_rcode_t rcode;
+ int ret;
skip_next_result:
- status = sql_store_result(handle, config);
- if (status != 0) {
- return status;
+ rcode = sql_store_result(handle, config);
+ if (rcode != RLM_SQL_OK) {
+ return rcode;
} else if (conn->result != NULL) {
DEBUG("rlm_sql_mysql: SQL statement returned unexpected result");
sql_free_result(handle, config);
}
- status = mysql_next_result(conn->sock);
- if (status == 0) {
+
+ ret = mysql_next_result(conn->sock);
+ if (ret == 0) {
/* there are more results */
goto skip_next_result;
- } else if (status > 0) {
+ } else if (ret > 0) {
ERROR("rlm_sql_mysql: Cannot get next result");
- ERROR("rlm_sql_mysql: MySQL error '%s'",
- mysql_error(conn->sock));
- return sql_check_error(status);
+ ERROR("rlm_sql_mysql: MySQL error '%s'", mysql_error(conn->sock));
+
+ return sql_check_error(ret);
}
#endif
- return 0;
+ return RLM_SQL_OK;
}
static sql_rcode_t sql_finish_select_query(rlm_sql_handle_t * handle, rlm_sql_config_t *config)
{
#if (MYSQL_VERSION_ID >= 40100)
- int status;
+ int ret;
rlm_sql_mysql_conn_t *conn = handle->conn;
#endif
sql_free_result(handle, config);
#if (MYSQL_VERSION_ID >= 40100)
- status = mysql_next_result(conn->sock);
- if (status == 0) {
+ ret = mysql_next_result(conn->sock);
+ if (ret == 0) {
/* there are more results */
sql_finish_query(handle, config);
- } else if (status > 0) {
+ } else if (ret > 0) {
ERROR("rlm_sql_mysql: Cannot get next result");
- ERROR("rlm_sql_mysql: MySQL error '%s'",
- mysql_error(conn->sock));
- return sql_check_error(status);
+ ERROR("rlm_sql_mysql: MySQL error '%s'", mysql_error(conn->sock));
+
+ return sql_check_error(ret);
}
#endif
- return 0;
+ return RLM_SQL_OK;
}
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-oracle-include-dir=DIR
- Directory where the oracle includes may be found
+ Directory where the oracle includes may be found
--with-oracle-lib-dir=DIR
- Directory where the oracle libraries may be found
+ Directory where the oracle libraries may be found
--with-oracle-dir=DIR Base directory where oracle is installed
Some influential environment variables:
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
if test x$with_rlm_sql_oracle != xno; then
- oracle_include_dir=
+ oracle_include_dir=
# Check whether --with-oracle-include-dir was given.
if test "${with_oracle_include_dir+set}" = set; then :
withval=$with_oracle_include_dir; case "$withval" in
- no)
- as_fn_error $? "Need oracle-include-dir" "$LINENO" 5
- ;;
- yes)
- ;;
- *)
- oracle_include_dir="$withval"
- ;;
- esac
+ no)
+ as_fn_error $? "Need oracle-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ oracle_include_dir="$withval"
+ ;;
+ esac
fi
- oracle_lib_dir=
+ oracle_lib_dir=
# Check whether --with-oracle-lib-dir was given.
if test "${with_oracle_lib_dir+set}" = set; then :
withval=$with_oracle_lib_dir; case "$withval" in
- no)
- as_fn_error $? "Need oracle-lib-dir" "$LINENO" 5
- ;;
- yes)
- ;;
- *)
- oracle_lib_dir="$withval"
- ;;
- esac
+ no)
+ as_fn_error $? "Need oracle-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ oracle_lib_dir="$withval"
+ ;;
+ esac
fi
# Check whether --with-oracle-dir was given.
if test "${with_oracle_dir+set}" = set; then :
withval=$with_oracle_dir; case "$withval" in
- no)
- as_fn_error $? "Need oracle-dir" "$LINENO" 5
- ;;
- yes)
- ;;
- *)
- oracle_lib_dir="$withval/lib"
- oracle_include_dir="$withval/include"
- ;;
- esac
+ no)
+ as_fn_error $? "Need oracle-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ oracle_lib_dir="$withval/lib"
+ oracle_include_dir="$withval/include"
+ ;;
+ esac
fi
smart_try_dir="$oracle_include_dir /usr/local/instaclient/include"
if test "x$ORACLE_HOME" != "x"; then
- smart_try_dir+="${ORACLE_HOME}/include"
+ smart_try_dir+="${ORACLE_HOME}/include"
fi
ac_ext=c
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=oci.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
fi
if test "x$ac_cv_header_oci_h" != "xyes"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: oracle headers not found. Use --with-oracle-include-dir=<path> or set ORACLE_HOME." >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: oracle headers not found. Use --with-oracle-include-dir=<path> or set ORACLE_HOME." >&5
$as_echo "$as_me: WARNING: oracle headers not found. Use --with-oracle-include-dir=<path> or set ORACLE_HOME." >&2;}
- fail="$fail oci.h"
+ fail="$fail oci.h"
fi
old_LIBS="$LIBS"
if test "x$oracle_lib_dir" != "x" ; then
- lib_path="${oracle_lib_dir} "
+ lib_path="${oracle_lib_dir} "
elif test "x$ORACLE_HOME" != "x" ; then
- lib_path="${ORACLE_HOME}/lib "
+ lib_path="${ORACLE_HOME}/lib "
fi
for path in $lib_path "/usr/local/instaclient/lib" "" "/opt/lib"; do
- for oracle_version in 11 10 9 ""; do
- if test "$path" != ""; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCIInitialize in nnz${oracle_version} in $path" >&5
+ for oracle_version in 11 10 9 ""; do
+ if test "$path" != ""; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCIInitialize in nnz${oracle_version} in $path" >&5
$as_echo_n "checking for OCIInitialize in nnz${oracle_version} in $path... " >&6; }
- else
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCIInitialize in nnz${oracle_version}" >&5
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCIInitialize in nnz${oracle_version}" >&5
$as_echo_n "checking for OCIInitialize in nnz${oracle_version}... " >&6; }
- fi
+ fi
- LIBS="$old_LIBS -L$path -lclntsh -lnnz${oracle_version}"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ LIBS="$old_LIBS -L$path -lclntsh -lnnz${oracle_version}"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <oci.h>
- static OCIEnv *p_env;
- static OCIError *p_err;
- static OCISvcCtx *p_svc;
- static OCIStmt *p_sql;
- static OCIDefine *p_dfn = (OCIDefine *) 0;
- static OCIBind *p_bnd = (OCIBind *) 0;
+ static OCIEnv *p_env;
+ static OCIError *p_err;
+ static OCISvcCtx *p_svc;
+ static OCIStmt *p_sql;
+ static OCIDefine *p_dfn = (OCIDefine *) 0;
+ static OCIBind *p_bnd = (OCIBind *) 0;
int
main ()
{
- int p_bvi;
- char p_sli[20];
- int rc;
- char errbuf[100];
- int errcode;
+ int p_bvi;
+ char p_sli[20];
+ int rc;
+ char errbuf[100];
+ int errcode;
- rc = OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, /* Initialize OCI */
- (dvoid * (*)(dvoid *, size_t)) 0,
- (dvoid * (*)(dvoid *, dvoid *, size_t))0,
- (void (*)(dvoid *, dvoid *)) 0 );
+ rc = OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, /* Initialize OCI */
+ (dvoid * (*)(dvoid *, size_t)) 0,
+ (dvoid * (*)(dvoid *, dvoid *, size_t))0,
+ (void (*)(dvoid *, dvoid *)) 0 );
;
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
- if test "x$mod_ldflags" != "x"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ if test "x$mod_ldflags" != "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
- break
- fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+ break
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
- done
+ done
- if test "x$mod_ldflags" != "x"; then
- break
- fi
+ if test "x$mod_ldflags" != "x"; then
+ break
+ fi
done
LIBS="$old_LIBS"
if test "x$mod_ldflags" = "x"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: oracle libraries not found. Use --with-oracle-lib-dir=<path> or set ORACLE_HOME." >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: oracle libraries not found. Use --with-oracle-lib-dir=<path> or set ORACLE_HOME." >&5
$as_echo "$as_me: WARNING: oracle libraries not found. Use --with-oracle-lib-dir=<path> or set ORACLE_HOME." >&2;}
- fail="$fail libclntsh libnnz[9-11]"
+ fail="$fail libclntsh libnnz[9-11]"
fi
targetname=rlm_sql_oracle
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
AC_ARG_WITH(oracle-include-dir,
[AS_HELP_STRING([--with-oracle-include-dir=DIR],
[Directory where the oracle includes may be found])],
- [case "$withval" in
- no)
- AC_MSG_ERROR(Need oracle-include-dir)
- ;;
- yes)
- ;;
- *)
- oracle_include_dir="$withval"
- ;;
- esac])
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need oracle-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ oracle_include_dir="$withval"
+ ;;
+ esac])
dnl extra argument: --with-oracle-lib-dir=DIR
oracle_lib_dir=
AC_ARG_WITH(oracle-lib-dir,
[AS_HELP_STRING([--with-oracle-lib-dir=DIR],
[Directory where the oracle libraries may be found])],
- [case "$withval" in
- no)
- AC_MSG_ERROR(Need oracle-lib-dir)
- ;;
- yes)
- ;;
- *)
- oracle_lib_dir="$withval"
- ;;
- esac])
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need oracle-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ oracle_lib_dir="$withval"
+ ;;
+ esac])
dnl extra argument: --with-oracle-dir=DIR
AC_ARG_WITH(oracle-dir,
[AS_HELP_STRING([--with-oracle-dir=DIR],
[Base directory where oracle is installed])],
- [case "$withval" in
- no)
- AC_MSG_ERROR(Need oracle-dir)
- ;;
- yes)
- ;;
- *)
- oracle_lib_dir="$withval/lib"
- oracle_include_dir="$withval/include"
- ;;
- esac])
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need oracle-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ oracle_lib_dir="$withval/lib"
+ oracle_include_dir="$withval/include"
+ ;;
+ esac])
dnl ############################################################
dnl # Check for header files
smart_try_dir="$oracle_include_dir /usr/local/instaclient/include"
if test "x$ORACLE_HOME" != "x"; then
- smart_try_dir+="${ORACLE_HOME}/include"
+ smart_try_dir+="${ORACLE_HOME}/include"
fi
FR_SMART_CHECK_INCLUDE(oci.h)
if test "x$ac_cv_header_oci_h" != "xyes"; then
- AC_MSG_WARN([oracle headers not found. Use --with-oracle-include-dir=<path> or set ORACLE_HOME.])
- fail="$fail oci.h"
+ AC_MSG_WARN([oracle headers not found. Use --with-oracle-include-dir=<path> or set ORACLE_HOME.])
+ fail="$fail oci.h"
fi
dnl ############################################################
old_LIBS="$LIBS"
if test "x$oracle_lib_dir" != "x" ; then
- lib_path="${oracle_lib_dir} "
+ lib_path="${oracle_lib_dir} "
elif test "x$ORACLE_HOME" != "x" ; then
- lib_path="${ORACLE_HOME}/lib "
+ lib_path="${ORACLE_HOME}/lib "
fi
for path in $lib_path "/usr/local/instaclient/lib" "" "/opt/lib"; do
- for oracle_version in 11 10 9 ""; do
- if test "$path" != ""; then
- AC_MSG_CHECKING([for OCIInitialize in nnz${oracle_version} in $path])
- else
- AC_MSG_CHECKING([for OCIInitialize in nnz${oracle_version}])
- fi
-
- LIBS="$old_LIBS -L$path -lclntsh -lnnz${oracle_version}"
- AC_TRY_LINK([#include <oci.h>
+ for oracle_version in 11 10 9 ""; do
+ if test "$path" != ""; then
+ AC_MSG_CHECKING([for OCIInitialize in nnz${oracle_version} in $path])
+ else
+ AC_MSG_CHECKING([for OCIInitialize in nnz${oracle_version}])
+ fi
+
+ LIBS="$old_LIBS -L$path -lclntsh -lnnz${oracle_version}"
+ AC_TRY_LINK([#include <oci.h>
- static OCIEnv *p_env;
- static OCIError *p_err;
- static OCISvcCtx *p_svc;
- static OCIStmt *p_sql;
- static OCIDefine *p_dfn = (OCIDefine *) 0;
- static OCIBind *p_bnd = (OCIBind *) 0;
- ],
- [
- int p_bvi;
- char p_sli[20];
- int rc;
- char errbuf[100];
- int errcode;
-
- rc = OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, /* Initialize OCI */
- (dvoid * (*)(dvoid *, size_t)) 0,
- (dvoid * (*)(dvoid *, dvoid *, size_t))0,
- (void (*)(dvoid *, dvoid *)) 0 );
+ static OCIEnv *p_env;
+ static OCIError *p_err;
+ static OCISvcCtx *p_svc;
+ static OCIStmt *p_sql;
+ static OCIDefine *p_dfn = (OCIDefine *) 0;
+ static OCIBind *p_bnd = (OCIBind *) 0;
+ ],
+ [
+ int p_bvi;
+ char p_sli[20];
+ int rc;
+ char errbuf[100];
+ int errcode;
+
+ rc = OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, /* Initialize OCI */
+ (dvoid * (*)(dvoid *, size_t)) 0,
+ (dvoid * (*)(dvoid *, dvoid *, size_t))0,
+ (void (*)(dvoid *, dvoid *)) 0 );
- ],
- [mod_ldflags="$LIBS"],
- )
- if test "x$mod_ldflags" != "x"; then
- AC_MSG_RESULT(yes)
- break
- fi
- AC_MSG_RESULT(no)
- done
-
- if test "x$mod_ldflags" != "x"; then
- break
- fi
+ ],
+ [mod_ldflags="$LIBS"],
+ )
+ if test "x$mod_ldflags" != "x"; then
+ AC_MSG_RESULT(yes)
+ break
+ fi
+ AC_MSG_RESULT(no)
+ done
+
+ if test "x$mod_ldflags" != "x"; then
+ break
+ fi
done
LIBS="$old_LIBS"
if test "x$mod_ldflags" = "x"; then
- AC_MSG_WARN([oracle libraries not found. Use --with-oracle-lib-dir=<path> or set ORACLE_HOME.])
- fail=["$fail libclntsh libnnz[9-11]"]
+ AC_MSG_WARN([oracle libraries not found. Use --with-oracle-lib-dir=<path> or set ORACLE_HOME.])
+ fail=["$fail libclntsh libnnz[9-11]"]
fi
targetname=modname
*/
if (OCILogon(conn->env, conn->error, &conn->ctx,
(OraText const *)config->sql_login, strlen(config->sql_login),
- (OraText const *)config->sql_password, strlen(config->sql_password),
- (OraText const *)config->sql_db, strlen(config->sql_db))) {
+ (OraText const *)config->sql_password, strlen(config->sql_password),
+ (OraText const *)config->sql_db, strlen(config->sql_db))) {
ERROR("rlm_sql_oracle: Oracle logon failed: '%s'", sql_error(handle, config));
return -1;
--- /dev/null
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Whether the PGRES_COPY_BOTH constant is defined */
+#undef HAVE_PGRES_COPY_BOTH
+
+/* Whether the PGRES_SINGLE_TUPLE constant is defined */
+#undef HAVE_PGRES_SINGLE_TUPLE
+
+/* Define to 1 if you have the `PQinitOpenSSL' function. */
+#undef HAVE_PQINITOPENSSL
+
+/* Define to 1 if you have the `PQinitSSL' function. */
+#undef HAVE_PQINITSSL
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
as_fn_set_status $ac_retval
} # ac_fn_c_try_link
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libpq-fe.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
fi
if test "x$ac_cv_header_libpqmfe_h" != "xyes"; then
- fail="$fail libpq-fe.h"
+ fail="$fail libpq-fe.h"
+ else
+ CPPFLAGS="$SMART_CPPFLAGS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PGRES_SINGLE_TUPLE" >&5
+$as_echo_n "checking for PGRES_SINGLE_TUPLE... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <libpq-fe.h>
+int
+main ()
+{
+
+ if (PGRES_SINGLE_TUPLE) return 0;
+ return 1;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+
+$as_echo "#define HAVE_PGRES_SINGLE_TUPLE 1" >>confdefs.h
+
+ { $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_ext
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PGRES_COPY_BOTH" >&5
+$as_echo_n "checking for PGRES_COPY_BOTH... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <libpq-fe.h>
+int
+main ()
+{
+
+ if (PGRES_COPY_BOTH) return 0;
+ return 1;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+
+$as_echo "#define HAVE_PGRES_COPY_BOTH 1" >>confdefs.h
+
+ { $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_ext
fi
smart_try_dir="$rlm_sql_postgresql_lib_dir /usr/lib /usr/local/pgsql/lib"
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lpq"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lpq"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libpq${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libpq.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
SMART_LIBS="$smart_lib $SMART_LIBS"
fi
- if test "x$ac_cv_lib_pq_PQconnectdb" != "xyes"; then
- fail="$fail libpq"
- fi
+ if test "x$ac_cv_lib_pq_PQconnectdb" != "xyes"; then
+ fail="$fail libpq"
+ fi
+ for ac_func in \
+ PQinitOpenSSL \
+ PQinitSSL \
+
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
targetname=rlm_sql_postgresql
else
+ac_config_headers="$ac_config_headers config.h"
+
unset ac_cv_env_LIBS_set
unset ac_cv_env_LIBS_value
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
# Let make expand exec_prefix.
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
-# Transform confdefs.h into DEFS.
-# Protect against shell expansion while executing Makefile rules.
-# Protect against Makefile macro expansion.
-#
-# If the first sed substitution is executed (which looks for macros that
-# take arguments), then branch to the quote section. Otherwise,
-# look for a macro that doesn't take arguments.
-ac_script='
-:mline
-/\\$/{
- N
- s,\\\n,,
- b mline
-}
-t clear
-:clear
-s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
-t quote
-s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
-t quote
-b any
-:quote
-s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
-s/\[/\\&/g
-s/\]/\\&/g
-s/\$/$$/g
-H
-:any
-${
- g
- s/^\n//
- s/\n/ /g
- p
-}
-'
-DEFS=`sed -n "$ac_script" confdefs.h`
-
+DEFS=-DHAVE_CONFIG_H
ac_libobjs=
ac_ltlibobjs=
"*) set x $ac_config_files; shift; ac_config_files=$*;;
esac
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
# Files that config.status was made for.
config_files="$ac_config_files"
+config_headers="$ac_config_headers"
_ACEOF
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
Configuration files:
$config_files
+Configuration headers:
+$config_headers
+
Report bugs to the package provider."
_ACEOF
esac
as_fn_append CONFIG_FILES " '$ac_optarg'"
ac_need_defaults=false;;
- --he | --h | --help | --hel | -h )
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
$as_echo "$ac_cs_usage"; exit ;;
-q | -quiet | --quiet | --quie | --qui | --qu | --q \
| -silent | --silent | --silen | --sile | --sil | --si | --s)
for ac_config_target in $ac_config_targets
do
case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
"all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
# bizarre bug on SunOS 4.1.3.
if $ac_need_defaults; then
test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
fi
# Have a temporary directory for convenience. Make it in the build tree
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
fi # test -n "$CONFIG_FILES"
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_tt"; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = "\a"
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
-eval set X " :F $CONFIG_FILES "
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS "
shift
for ac_tag
do
esac \
|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
;;
-
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+ } >"$ac_tmp/config.h" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$ac_tmp/config.h" "$ac_file" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
+ fi
+ ;;
esac
smart_try_dir="$rlm_sql_postgresql_include_dir /usr/include/postgresql /usr/local/pgsql/include /usr/include/pgsql"
FR_SMART_CHECK_INCLUDE(libpq-fe.h)
if test "x$ac_cv_header_libpqmfe_h" != "xyes"; then
- fail="$fail libpq-fe.h"
+ fail="$fail libpq-fe.h"
+ else
+ CPPFLAGS="$SMART_CPPFLAGS"
+ AC_MSG_CHECKING([for PGRES_SINGLE_TUPLE])
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([#include <libpq-fe.h>], [[
+ if (PGRES_SINGLE_TUPLE) return 0;
+ return 1;
+ ]])],
+ [
+ AC_DEFINE([HAVE_PGRES_SINGLE_TUPLE], [1], [Whether the PGRES_SINGLE_TUPLE constant is defined])
+ AC_MSG_RESULT(yes)
+ ],
+ [
+ AC_MSG_RESULT(no)
+ ])
+
+ AC_MSG_CHECKING([for PGRES_COPY_BOTH])
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([#include <libpq-fe.h>], [[
+ if (PGRES_COPY_BOTH) return 0;
+ return 1;
+ ]])],
+ [
+ AC_DEFINE([HAVE_PGRES_COPY_BOTH], [1], [Whether the PGRES_COPY_BOTH constant is defined])
+ AC_MSG_RESULT(yes)
+ ],
+ [
+ AC_MSG_RESULT(no)
+ ])
fi
smart_try_dir="$rlm_sql_postgresql_lib_dir /usr/lib /usr/local/pgsql/lib"
FR_SMART_CHECK_LIB(pq, PQconnectdb)
- if test "x$ac_cv_lib_pq_PQconnectdb" != "xyes"; then
- fail="$fail libpq"
- fi
-
+ if test "x$ac_cv_lib_pq_PQconnectdb" != "xyes"; then
+ fail="$fail libpq"
+ fi
+ AC_CHECK_FUNCS(\
+ PQinitOpenSSL \
+ PQinitSSL \
+ )
targetname=modname
else
targetname=
AC_SUBST(mod_ldflags)
AC_SUBST(mod_cflags)
AC_SUBST(targetname)
+AC_CONFIG_HEADER(config.h)
AC_OUTPUT(all.mk)
#include <sys/stat.h>
#include <libpq-fe.h>
+#include <postgres_ext.h>
+
+#include "config.h"
#include "rlm_sql.h"
#include "sql_postgresql.h"
+#ifndef NAMEDATALEN
+# define NAMEDATALEN 64
+#endif
+
+typedef struct rlm_sql_postgres_config {
+ char const *db_string;
+ bool send_application_name;
+} rlm_sql_postgres_config_t;
+
typedef struct rlm_sql_postgres_conn {
- char const *dbstring; //!< String describing parameters for the connection
PGconn *db;
PGresult *result;
int cur_row;
char **row;
} rlm_sql_postgres_conn_t;
-/* Internal function. Return true if the postgresql status value
- * indicates successful completion of the query. Return false otherwise
-static int
-status_is_ok(ExecStatusType status)
+static CONF_PARSER driver_config[] = {
+ { "send_application_name", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sql_postgres_config_t, send_application_name), "yes" },
+
+ { NULL, -1, 0, NULL, NULL }
+};
+
+static int mod_instantiate(CONF_SECTION *conf, UNUSED rlm_sql_config_t *config)
{
- return status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK;
-}
-*/
+#if defined(HAVE_OPENSSL_CRYPTO_H) && (defined(HAVE_PQINITOPENSSL) || defined(HAVE_PQINITSSL))
+ static bool ssl_init = false;
+#endif
+
+ rlm_sql_postgres_config_t *driver;
+ char application_name[NAMEDATALEN];
+ char *db_string;
+
+#if defined(HAVE_OPENSSL_CRYPTO_H) && (defined(HAVE_PQINITOPENSSL) || defined(HAVE_PQINITSSL))
+ if (!ssl_init) {
+# ifdef HAVE_PQINITOPENSSL
+ PQinitOpenSSL(0, 0);
+# else
+ PQinitSSL(0);
+# endif
+ ssl_init = true;
+ }
+#endif
+
+ MEM(driver = config->driver = talloc_zero(config, rlm_sql_postgres_config_t));
+ if (cf_section_parse(conf, driver, driver_config) < 0) {
+ return -1;
+ }
+
+ db_string = strchr(config->sql_db, '=') ?
+ talloc_typed_strdup(driver, config->sql_db) :
+ talloc_typed_asprintf(driver, "dbname='%s'", config->sql_db);
+
+ if (config->sql_server[0] != '\0') {
+ db_string = talloc_asprintf_append(db_string, " host='%s'", config->sql_server);
+ }
+
+ if (config->sql_port[0] != '\0') {
+ db_string = talloc_asprintf_append(db_string, " port=%s", config->sql_port);
+ }
+
+ if (config->sql_login[0] != '\0') {
+ db_string = talloc_asprintf_append(db_string, " user='%s'", config->sql_login);
+ }
+
+ if (config->sql_password[0] != '\0') {
+ db_string = talloc_asprintf_append(db_string, " password='%s'", config->sql_password);
+ }
+ /*
+ * Allow the user to set their own, or disable it
+ */
+ if (driver->send_application_name) {
+ snprintf(application_name, sizeof(application_name),
+ "FreeRADIUS " RADIUSD_VERSION_STRING " - %s (%s)", progname, config->xlat_name);
+ db_string = talloc_asprintf_append(db_string, " application_name='%s'", application_name);
+ }
+ driver->db_string = db_string;
+
+ return 0;
+}
-/* Internal function. Return the number of affected rows of the result
- * as an int instead of the string that postgresql provides */
+/** Return the number of affected rows of the result as an int instead of the string that postgresql provides
+ *
+ */
static int affected_rows(PGresult * result)
{
return atoi(PQcmdTuples(result));
}
-/* Internal function. Free the row of the current result that's stored
- * in the conn struct. */
+/** Free the row of the current result that's stored in the conn struct
+ *
+ */
static void free_result_row(rlm_sql_postgres_conn_t *conn)
{
+ TALLOC_FREE(conn->row);
+ conn->num_fields = 0;
+}
+
+#if defined(PG_DIAG_SQLSTATE) && defined(PG_DIAG_MESSAGE_PRIMARY)
+static sql_rcode_t sql_classify_error(PGresult const *result)
+{
int i;
- if (conn->row != NULL) {
- for (i = conn->num_fields-1; i >= 0; i--) {
- if (conn->row[i] != NULL) {
- free(conn->row[i]);
- }
- }
- free((char*)conn->row);
- conn->row = NULL;
- conn->num_fields = 0;
+
+ char *errorcode;
+ char *errormsg;
+
+ /*
+ * Check the error code to see if we should reconnect or not
+ * Error Code table taken from:
+ * http://www.postgresql.org/docs/8.1/interactive/errcodes-appendix.html
+ */
+ errorcode = PQresultErrorField(result, PG_DIAG_SQLSTATE);
+ errormsg = PQresultErrorField(result, PG_DIAG_MESSAGE_PRIMARY);
+ if (!errorcode) {
+ ERROR("rlm_sql_postgresql: Error occurred, but unable to retrieve error code");
+ return RLM_SQL_ERROR;
}
-}
+ /* SUCCESSFUL COMPLETION */
+ if (strcmp("00000", errorcode) == 0) {
+ return RLM_SQL_OK;
+ }
-/*************************************************************************
-* Function: check_fatal_error
-*
-* Purpose: Check error type and behave accordingly
-*
-*************************************************************************/
+ /* WARNING */
+ if (strcmp("01000", errorcode) == 0) {
+ WARN("%s", errormsg);
+ return RLM_SQL_OK;
+ }
-static int check_fatal_error (char *errorcode)
-{
- int x = 0;
+ /* UNIQUE VIOLATION */
+ if (strcmp("23505", errorcode) == 0) {
+ return RLM_SQL_DUPLICATE;
+ }
- /*
- Check the error code to see if we should reconnect or not
- Error Code table taken from
- http://www.postgresql.org/docs/8.1/interactive/errcodes-appendix.html
- */
-
- if (!errorcode) return -1;
-
- while(errorcodes[x].errorcode != NULL){
- if (strcmp(errorcodes[x].errorcode, errorcode) == 0){
- DEBUG("rlm_sql_postgresql: Postgresql Fatal Error: [%s: %s] Occurred!!", errorcode, errorcodes[x].meaning);
- if (errorcodes[x].shouldreconnect == 1)
- return RLM_SQL_RECONNECT;
- else
- return -1;
+ /* others */
+ for (i = 0; errorcodes[i].errorcode != NULL; i++) {
+ if (strcmp(errorcodes[i].errorcode, errorcode) == 0) {
+ ERROR("rlm_sql_postgresql: %s: %s", errorcode, errorcodes[i].meaning);
+
+ return (errorcodes[i].reconnect == true) ?
+ RLM_SQL_RECONNECT :
+ RLM_SQL_ERROR;
}
- x++;
}
- DEBUG("rlm_sql_postgresql: Postgresql Fatal Error: [%s] Occurred!!", errorcode);
- /* We don't seem to have a matching error class/code */
- return -1;
+ ERROR("rlm_sql_postgresql: Can't classify: %s", errorcode);
+ return RLM_SQL_ERROR;
}
+# else
+static sql_rcode_t sql_classify_error(UNUSED PGresult const *result)
+{
+ ERROR("rlm_sql_postgresql: Error occurred, no more information available, rebuild with newer libpq");
+ return RLM_SQL_ERROR;
+}
+#endif
static int sql_socket_destructor(void *c)
{
/* PQfinish also frees the memory used by the PGconn structure */
PQfinish(conn->db);
+ conn->db = NULL;
return 0;
}
* Purpose: Establish connection to the db
*
*************************************************************************/
-static int sql_init_socket(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
- char *dbstring;
+static int CC_HINT(nonnull) sql_init_socket(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ rlm_sql_postgres_config_t *driver = config->driver;
rlm_sql_postgres_conn_t *conn;
-#ifdef HAVE_OPENSSL_CRYPTO_H
- static bool ssl_init = false;
-
- if (!ssl_init) {
- PQinitOpenSSL(0, 0);
- ssl_init = true;
- }
-#endif
-
MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_postgres_conn_t));
talloc_set_destructor((void *) conn, sql_socket_destructor);
- dbstring = strchr(config->sql_db, '=') ?
- talloc_strdup(conn, config->sql_db) :
- talloc_asprintf(conn, "dbname='%s'", config->sql_db);
-
- if (config->sql_server[0] != '\0') {
- dbstring = talloc_asprintf_append(dbstring, " host='%s'", config->sql_server);
- }
-
- if (config->sql_port[0] != '\0') {
- dbstring = talloc_asprintf_append(dbstring, " port=%s", config->sql_port);
- }
-
- if (config->sql_login[0] != '\0') {
- dbstring = talloc_asprintf_append(dbstring, " user='%s'", config->sql_login);
- }
-
- if (config->sql_password[0] != '\0') {
- dbstring = talloc_asprintf_append(dbstring, " password='%s'", config->sql_password);
+ DEBUG2("rlm_sql_postgresql: Connecting using parameters: %s", driver->db_string);
+ conn->db = PQconnectdb(driver->db_string);
+ if (!conn->db) {
+ ERROR("rlm_sql_postgresql: Connection failed: Out of memory");
+ return -1;
}
-
- conn->dbstring = dbstring;
- conn->db = PQconnectdb(dbstring);
- DEBUG2("rlm_sql_postgresql: Connecting using parameters: %s", dbstring);
- if (!conn->db || (PQstatus(conn->db) != CONNECTION_OK)) {
+ if (PQstatus(conn->db) != CONNECTION_OK) {
ERROR("rlm_sql_postgresql: Connection failed: %s", PQerrorMessage(conn->db));
+ PQfinish(conn->db);
+ conn->db = NULL;
return -1;
}
+
DEBUG2("Connected to database '%s' on '%s' server version %i, protocol version %i, backend PID %i ",
PQdb(conn->db), PQhost(conn->db), PQserverVersion(conn->db), PQprotocolVersion(conn->db),
PQbackendPID(conn->db));
* Purpose: Issue a query to the database
*
*************************************************************************/
-static sql_rcode_t sql_query(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config, char const *query)
+static CC_HINT(nonnull) sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config,
+ char const *query)
{
rlm_sql_postgres_conn_t *conn = handle->conn;
+ ExecStatusType status;
int numfields = 0;
- char *errorcode;
- char *errormsg;
if (!conn->db) {
ERROR("rlm_sql_postgresql: Socket not connected");
return RLM_SQL_RECONNECT;
}
+ /*
+ * Returns a PGresult pointer or possibly a null pointer.
+ * A non-null pointer will generally be returned except in
+ * out-of-memory conditions or serious errors such as inability
+ * to send the command to the server. If a null pointer is
+ * returned, it should be treated like a PGRES_FATAL_ERROR
+ * result.
+ */
conn->result = PQexec(conn->db, query);
- /*
- * Returns a PGresult pointer or possibly a null pointer.
- * A non-null pointer will generally be returned except in
- * out-of-memory conditions or serious errors such as inability
- * to send the command to the server. If a null pointer is
- * returned, it should be treated like a PGRES_FATAL_ERROR
- * result.
- */
- if (!conn->result) {
- ERROR("rlm_sql_postgresql: PostgreSQL Query failed Error: %s",
- PQerrorMessage(conn->db));
- /* As this error COULD be a connection error OR an out-of-memory
- * condition return value WILL be wrong SOME of the time regardless!
- * Pick your poison....
- */
- return RLM_SQL_RECONNECT;
- } else {
- ExecStatusType status = PQresultStatus(conn->result);
- DEBUG("rlm_sql_postgresql: Status: %s", PQresStatus(status));
-
- switch (status){
-
- case PGRES_COMMAND_OK:
- /*Successful completion of a command returning no data.*/
-
- /*affected_rows function only returns
- the number of affected rows of a command
- returning no data...
- */
- conn->affected_rows = affected_rows(conn->result);
- DEBUG("rlm_sql_postgresql: query affected rows = %i", conn->affected_rows);
- return 0;
-
- break;
-
- case PGRES_TUPLES_OK:
- /*Successful completion of a command returning data (such as a SELECT or SHOW).*/
-
- conn->cur_row = 0;
- conn->affected_rows = PQntuples(conn->result);
- numfields = PQnfields(conn->result); /*Check row storing functions..*/
- DEBUG("rlm_sql_postgresql: query affected rows = %i , fields = %i", conn->affected_rows, numfields);
- return 0;
-
- break;
- case PGRES_BAD_RESPONSE:
- /*The server's response was not understood.*/
- DEBUG("rlm_sql_postgresql: Bad Response From Server!!");
- return -1;
-
- break;
-
- case PGRES_NONFATAL_ERROR:
- /*A nonfatal error (a notice or warning) occurred. Possibly never returns*/
-
- return -1;
-
- break;
+ /*
+ * As this error COULD be a connection error OR an out-of-memory
+ * condition return value WILL be wrong SOME of the time
+ * regardless! Pick your poison...
+ */
+ if (!conn->result) {
+ ERROR("rlm_sql_postgresql: Failed getting query result: %s", PQerrorMessage(conn->db));
+ return RLM_SQL_RECONNECT;
+ }
- case PGRES_FATAL_ERROR:
-#if defined(PG_DIAG_SQLSTATE) && defined(PG_DIAG_MESSAGE_PRIMARY)
- /*A fatal error occurred.*/
+ status = PQresultStatus(conn->result);
+ DEBUG("rlm_sql_postgresql: Status: %s", PQresStatus(status));
- errorcode = PQresultErrorField(conn->result, PG_DIAG_SQLSTATE);
- errormsg = PQresultErrorField(conn->result, PG_DIAG_MESSAGE_PRIMARY);
- DEBUG("rlm_sql_postgresql: Error %s", errormsg);
- return check_fatal_error(errorcode);
+ switch (status){
+ /*
+ * Successful completion of a command returning no data.
+ */
+ case PGRES_COMMAND_OK:
+ /*
+ * Affected_rows function only returns the number of affected rows of a command
+ * returning no data...
+ */
+ conn->affected_rows = affected_rows(conn->result);
+ DEBUG("rlm_sql_postgresql: query affected rows = %i", conn->affected_rows);
+ return RLM_SQL_OK;
+ /*
+ * Successful completion of a command returning data (such as a SELECT or SHOW).
+ */
+#ifdef HAVE_PGRES_SINGLE_TUPLE
+ case PGRES_SINGLE_TUPLE:
#endif
+ case PGRES_TUPLES_OK:
+ conn->cur_row = 0;
+ conn->affected_rows = PQntuples(conn->result);
+ numfields = PQnfields(conn->result); /*Check row storing functions..*/
+ DEBUG("rlm_sql_postgresql: query affected rows = %i , fields = %i", conn->affected_rows, numfields);
+ return RLM_SQL_OK;
+
+#ifdef HAVE_PGRES_COPY_BOTH
+ case PGRES_COPY_BOTH:
+#endif
+ case PGRES_COPY_OUT:
+ case PGRES_COPY_IN:
+ DEBUG("rlm_sql_postgresql: Data transfer started");
+ return RLM_SQL_OK;
- break;
-
- default:
- /* FIXME: An unhandled error occurred.*/
-
- /* PGRES_EMPTY_QUERY PGRES_COPY_OUT PGRES_COPY_IN */
-
- return -1;
-
- break;
+ /*
+ * Weird.. this shouldn't happen.
+ */
+ case PGRES_EMPTY_QUERY:
+ ERROR("rlm_sql_postgresql: Empty query");
+ return RLM_SQL_QUERY_ERROR;
+ /*
+ * The server's response was not understood.
+ */
+ case PGRES_BAD_RESPONSE:
+ ERROR("rlm_sql_postgresql: Bad Response From Server");
+ return RLM_SQL_RECONNECT;
- }
- /*
- Note to self ... sql_store_result returns 0 anyway
- after setting the handle->affected_rows..
- sql_num_fields returns 0 at worst case which means the check below
- has a really small chance to return false..
- lets remove it then .. yuck!!
- */
- /*
- } else {
- if ((sql_store_result(handle, config) == 0)
- && (sql_num_fields(handle, config) >= 0))
- return 0;
- else
- return -1;
- }
- */
+ case PGRES_NONFATAL_ERROR:
+ case PGRES_FATAL_ERROR:
+ return sql_classify_error(conn->result);
}
- return -1;
+
+ return RLM_SQL_ERROR;
}
conn->num_fields = records;
if ((PQntuples(conn->result) > 0) && (records > 0)) {
- conn->row = (char **)rad_malloc((records+1)*sizeof(char *));
- memset(conn->row, '\0', (records+1)*sizeof(char *));
-
+ conn->row = talloc_zero_array(conn, char *, records + 1);
for (i = 0; i < records; i++) {
len = PQgetlength(conn->result, conn->cur_row, i);
- conn->row[i] = (char *)rad_malloc(len+1);
- memset(conn->row[i], '\0', len+1);
- strlcpy(conn->row[i], PQgetvalue(conn->result, conn->cur_row,i),len + 1);
+ conn->row[i] = talloc_array(conn->row, char, len + 1);
+ strlcpy(conn->row[i], PQgetvalue(conn->result, conn->cur_row, i),len + 1);
}
conn->cur_row++;
handle->row = conn->row;
rlm_sql_postgres_conn_t *conn = handle->conn;
- if (conn->result) {
+ if (conn->result != NULL) {
PQclear(conn->result);
conn->result = NULL;
}
/*************************************************************************
*
- * Function: sql_finish_query
- *
- * Purpose: End the query, such as freeing memory
- *
- *************************************************************************/
-static sql_rcode_t sql_finish_query(rlm_sql_handle_t * handle, rlm_sql_config_t *config) {
-
- return sql_free_result(handle, config);
-}
-
-/*************************************************************************
- *
- * Function: sql_finish_select_query
- *
- * Purpose: End the select query, such as freeing memory or result
- *
- *************************************************************************/
-static sql_rcode_t sql_finish_select_query(rlm_sql_handle_t * handle, rlm_sql_config_t *config) {
-
- return sql_free_result(handle, config);
-}
-
-
-/*************************************************************************
- *
* Function: sql_affected_rows
*
* Purpose: Return the number of rows affected by the last query.
/* Exported to rlm_sql */
rlm_sql_module_t rlm_sql_postgresql = {
"rlm_sql_postgresql",
- NULL,
+ mod_instantiate,
sql_init_socket,
sql_query,
sql_select_query,
sql_fetch_row,
NULL, /* sql_free_result */
sql_error,
- sql_finish_query,
- sql_finish_select_query,
+ sql_free_result,
+ sql_free_result,
sql_affected_rows,
};
RCSIDH(sql_postgresql_h, "$Id$")
-/**************************************************
-* Error Codes and required information Lookup table
-* Does this shite ever needed? Lets c..
-***************************************************/
+/** Error Codes and required information
+ *
+ */
typedef struct pgsql_error{
- char const *errorcode;
- char const *meaning;
- int shouldreconnect;
-}pgerror;
+ char const *errorcode; //!< 5 char error code from PG_DIAG_SQLSTATE.
+ char const *meaning; //!< Verbose description.
+ bool reconnect; //!< Should reconnect socket when receiving this error.
+} pgerror;
pgerror errorcodes[]=
{
- { "1000", "WARNING", 0, },
- { "0100C", "DYNAMIC RESULT SETS RETURNED", 0, },
- { "1008", "IMPLICIT ZERO BIT PADDING", 0, },
- { "1003", "NULL VALUE ELIMINATED IN SET FUNCTION", 0, },
- { "1007", "PRIVILEGE NOT GRANTED", 0, },
- { "1006", "PRIVILEGE NOT REVOKED", 0, },
- { "1004", "STRING DATA RIGHT TRUNCATION", 0, },
- { "01P01", "DEPRECATED FEATURE", 0, },
-
- { "2000", "NO DATA", 0, },
- { "2001", "NO ADDITIONAL DYNAMIC RESULT SETS RETURNED", 0, },
-
- { "3000", "SQL STATEMENT NOT YET COMPLETE", 0, },
-
- { "8000", "CONNECTION EXCEPTION", 0, },
- { "8003", "CONNECTION DOES NOT EXIST", 0, },
- { "8006", "CONNECTION FAILURE", 0, },
- { "8001", "SQLCLIENT UNABLE TO ESTABLISH SQLCONNECTION", 0, },
- { "8004", "SQLSERVER REJECTED ESTABLISHMENT OF SQLCONNECTION", 0, },
- { "8007", "TRANSACTION RESOLUTION UNKNOWN", 0, },
- { "08P01", "PROTOCOL VIOLATION", 0, },
-
- { "9000", "TRIGGERED ACTION EXCEPTION", 0, },
-
- { "0A000", "FEATURE NOT SUPPORTED", 0, },
-
- { "0B000", "INVALID TRANSACTION INITIATION", 0, },
-
- { "0F000", "LOCATOR EXCEPTION", 0, },
- { "0F001", "INVALID LOCATOR SPECIFICATION", 0, },
-
- { "0L000", "INVALID GRANTOR", 0, },
- { "0LP01", "INVALID GRANT OPERATION", 0, },
-
- { "21000", "CARDINALITY VIOLATION", 0, },
-
- { "22000", "DATA EXCEPTION", 0, },
- { "2202E", "ARRAY SUBSCRIPT ERROR", 0, },
- { "22021", "CHARACTER NOT IN REPERTOIRE", 0, },
- { "22008", "DATETIME FIELD OVERFLOW", 0, },
- { "22012", "DIVISION BY ZERO", 0, },
- { "22005", "ERROR IN ASSIGNMENT", 0, },
- { "2200B", "ESCAPE CHARACTER CONFLICT", 0, },
- { "22022", "INDICATOR OVERFLOW", 0, },
- { "22015", "INTERVAL FIELD OVERFLOW", 0, },
- { "2201E", "INVALID ARGUMENT FOR LOGARITHM", 0, },
- { "2201F", "INVALID ARGUMENT FOR POWER FUNCTION", 0, },
- { "2201G", "INVALID ARGUMENT FOR WIDTH BUCKET FUNCTION", 0, },
- { "22018", "INVALID CHARACTER VALUE FOR CAST", 0, },
- { "22007", "INVALID DATETIME FORMAT", 0, },
- { "22019", "INVALID ESCAPE CHARACTER", 0, },
- { "2200D", "INVALID ESCAPE OCTET", 0, },
- { "22025", "INVALID ESCAPE SEQUENCE", 0, },
- { "22P06", "NONSTANDARD USE OF ESCAPE CHARACTER", 0, },
- { "22010", "INVALID INDICATOR PARAMETER VALUE", 0, },
- { "22020", "INVALID LIMIT VALUE", 0, },
- { "22023", "INVALID PARAMETER VALUE", 0, },
- { "2201B", "INVALID REGULAR EXPRESSION", 0, },
- { "22009", "INVALID TIME ZONE DISPLACEMENT VALUE", 0, },
- { "2200C", "INVALID USE OF ESCAPE CHARACTER", 0, },
- { "2200G", "MOST SPECIFIC TYPE MISMATCH", 0, },
- { "22004", "NULL VALUE NOT ALLOWED", 0, },
- { "22002", "NULL VALUE NO INDICATOR PARAMETER", 0, },
- { "22003", "NUMERIC VALUE OUT OF RANGE", 0, },
- { "22026", "STRING DATA LENGTH MISMATCH", 0, },
- { "22001", "STRING DATA RIGHT TRUNCATION", 0, },
- { "22011", "SUBSTRING ERROR", 0, },
- { "22027", "TRIM ERROR", 0, },
- { "22024", "UNTERMINATED C STRING", 0, },
- { "2200F", "ZERO LENGTH CHARACTER STRING", 0, },
- { "22P01", "FLOATING POINT EXCEPTION", 0, },
- { "22P02", "INVALID TEXT REPRESENTATION", 0, },
- { "22P03", "INVALID BINARY REPRESENTATION", 0, },
- { "22P04", "BAD COPY FILE FORMAT", 0, },
- { "22P05", "UNTRANSLATABLE CHARACTER", 0, },
-
- { "23000", "INTEGRITY CONSTRAINT VIOLATION", 0, },
- { "23001", "RESTRICT VIOLATION", 0, },
- { "23502", "NOT NULL VIOLATION", 0, },
- { "23503", "FOREIGN KEY VIOLATION", 0, },
- { "23505", "UNIQUE VIOLATION", 0, },
- { "23514", "CHECK VIOLATION", 0, },
-
- { "24000", "INVALID CURSOR STATE", 0, },
-
- { "25000", "INVALID TRANSACTION STATE", 0, },
- { "25001", "ACTIVE SQL TRANSACTION", 0, },
- { "25002", "BRANCH TRANSACTION ALREADY ACTIVE", 0, },
- { "25008", "HELD CURSOR REQUIRES SAME ISOLATION LEVEL", 0, },
- { "25003", "INAPPROPRIATE ACCESS MODE FOR BRANCH TRANSACTION", 0, },
- { "25004", "INAPPROPRIATE ISOLATION LEVEL FOR BRANCH TRANSACTION", 0, },
- { "25005", "NO ACTIVE SQL TRANSACTION FOR BRANCH TRANSACTION", 0, },
- { "25006", "READ ONLY SQL TRANSACTION", 0, },
- { "25007", "SCHEMA AND DATA STATEMENT MIXING NOT SUPPORTED", 0, },
- { "25P01", "NO ACTIVE SQL TRANSACTION", 0, },
- { "25P02", "IN FAILED SQL TRANSACTION", 0, },
-
- { "26000", "INVALID SQL STATEMENT NAME", 0, },
-
- { "27000", "TRIGGERED DATA CHANGE VIOLATION", 0, },
-
- { "28000", "INVALID AUTHORIZATION SPECIFICATION", 0, },
-
- { "2B000", "DEPENDENT PRIVILEGE DESCRIPTORS STILL EXIST", 0, },
- { "2BP01", "DEPENDENT OBJECTS STILL EXIST", 0, },
-
- { "2D000", "INVALID TRANSACTION TERMINATION", 0, },
-
- { "2F000", "SQL ROUTINE EXCEPTION", 0, },
- { "2F005", "FUNCTION EXECUTED NO RETURN STATEMENT", 0, },
- { "2F002", "MODIFYING SQL DATA NOT PERMITTED", 0, },
- { "2F003", "PROHIBITED SQL STATEMENT ATTEMPTED", 0, },
- { "2F004", "READING SQL DATA NOT PERMITTED", 0, },
-
- { "34000", "INVALID CURSOR NAME", 0, },
-
- { "38000", "EXTERNAL ROUTINE EXCEPTION", 0, },
- { "38001", "CONTAINING SQL NOT PERMITTED", 0, },
- { "38002", "MODIFYING SQL DATA NOT PERMITTED", 0, },
- { "38003", "PROHIBITED SQL STATEMENT ATTEMPTED", 0, },
- { "38004", "READING SQL DATA NOT PERMITTED", 0, },
-
- { "39000", "EXTERNAL ROUTINE INVOCATION EXCEPTION", 0, },
- { "39001", "INVALID SQLSTATE RETURNED", 0, },
- { "39004", "NULL VALUE NOT ALLOWED", 0, },
- { "39P01", "TRIGGER PROTOCOL VIOLATED", 0, },
- { "39P02", "SRF PROTOCOL VIOLATED", 0, },
-
- { "3B000", "SAVEPOINT EXCEPTION", 0, },
- { "3B001", "INVALID SAVEPOINT SPECIFICATION", 0, },
-
- { "3D000", "INVALID CATALOG NAME", 0, },
- { "3F000", "INVALID SCHEMA NAME", 0, },
-
- { "40000", "TRANSACTION ROLLBACK", 0, },
- { "40002", "TRANSACTION INTEGRITY CONSTRAINT VIOLATION", 0, },
- { "40001", "SERIALIZATION FAILURE", 0, },
- { "40003", "STATEMENT COMPLETION UNKNOWN", 0, },
- { "40P01", "DEADLOCK DETECTED", 0, },
-
- { "44000", "WITH CHECK OPTION VIOLATION", 0, },
-
- { "53000", "INSUFFICIENT RESOURCES", 0, },
- { "53100", "DISK FULL", 0, },
- { "53200", "OUT OF MEMORY", 0, },
- { "53300", "TOO MANY CONNECTIONS", 0, },
-
- { "54000", "PROGRAM LIMIT EXCEEDED", 0, },
- { "54001", "STATEMENT TOO COMPLEX", 0, },
- { "54011", "TOO MANY COLUMNS", 0, },
- { "54023", "TOO MANY ARGUMENTS", 0, },
-
- { "55000", "OBJECT NOT IN PREREQUISITE STATE", 0, },
- { "55006", "OBJECT IN USE", 0, },
- { "55P02", "CANT CHANGE RUNTIME PARAM", 0, },
- { "55P03", "LOCK NOT AVAILABLE", 0, },
-
- { "57000", "OPERATOR INTERVENTION", 1, },
- { "57014", "QUERY CANCELED", 1, },
- { "57P01", "ADMIN SHUTDOWN", 1, },
- { "57P02", "CRASH SHUTDOWN", 1, },
- { "57P03", "CANNOT CONNECT NOW", 1, },
-
- { "58030", "IO ERROR", 1, },
- { "58P01", "UNDEFINED FILE", 1, },
- { "58P02", "DUPLICATE FILE", 1, },
-
- { "F0000", "CONFIG FILE ERROR", 1, },
- { "F0001", "LOCK FILE EXISTS", 1, },
-
- { "P0000", "PLPGSQL ERROR", 0, },
- { "P0001", "RAISE EXCEPTION", 0, },
-
- { "42000", "SYNTAX ERROR OR ACCESS RULE VIOLATION", 0, },
- { "42601", "SYNTAX ERROR", 0, },
- { "42501", "INSUFFICIENT PRIVILEGE", 0, },
- { "42846", "CANNOT COERCE", 0, },
- { "42803", "GROUPING ERROR", 0, },
- { "42830", "INVALID FOREIGN KEY", 0, },
- { "42602", "INVALID NAME", 0, },
- { "42622", "NAME TOO LONG", 0, },
- { "42939", "RESERVED NAME", 0, },
- { "42804", "DATATYPE MISMATCH", 0, },
- { "42P18", "INDETERMINATE DATATYPE", 0, },
- { "42809", "WRONG OBJECT TYPE", 0, },
- { "42703", "UNDEFINED COLUMN", 0, },
- { "42883", "UNDEFINED FUNCTION", 0, },
- { "42P01", "UNDEFINED TABLE", 0, },
- { "42P02", "UNDEFINED PARAMETER", 0, },
- { "42704", "UNDEFINED OBJECT", 0, },
- { "42701", "DUPLICATE COLUMN", 0, },
- { "42P03", "DUPLICATE CURSOR", 0, },
- { "42P04", "DUPLICATE DATABASE", 0, },
- { "42723", "DUPLICATE FUNCTION", 0, },
- { "42P05", "DUPLICATE PREPARED STATEMENT", 0, },
- { "42P06", "DUPLICATE SCHEMA", 0, },
- { "42P07", "DUPLICATE TABLE", 0, },
- { "42712", "DUPLICATE ALIAS", 0, },
- { "42710", "DUPLICATE OBJECT", 0, },
- { "42702", "AMBIGUOUS COLUMN", 0, },
- { "42725", "AMBIGUOUS FUNCTION", 0, },
- { "42P08", "AMBIGUOUS PARAMETER", 0, },
- { "42P09", "AMBIGUOUS ALIAS", 0, },
- { "42P10", "INVALID COLUMN REFERENCE", 0, },
- { "42611", "INVALID COLUMN DEFINITION", 0, },
- { "42P11", "INVALID CURSOR DEFINITION", 0, },
- { "42P12", "INVALID DATABASE DEFINITION", 0, },
- { "42P13", "INVALID FUNCTION DEFINITION", 0, },
- { "42P14", "INVALID PREPARED STATEMENT DEFINITION", 0, },
- { "42P15", "INVALID SCHEMA DEFINITION", 0, },
- { "42P16", "INVALID TABLE DEFINITION", 0, },
- { "42P17", "INVALID OBJECT DEFINITION", 0, },
-
- { "XX000", "INTERNAL ERROR", 0, },
- { "XX001", "DATA CORRUPTED", 0, },
- { "XX002", "INDEX CORRUPTED", 0, },
+ { "0100C", "DYNAMIC RESULT SETS RETURNED", false },
+ { "01008", "IMPLICIT ZERO BIT PADDING", false },
+ { "01003", "NULL VALUE ELIMINATED IN SET FUNCTION", false },
+ { "01007", "PRIVILEGE NOT GRANTED", false },
+ { "01006", "PRIVILEGE NOT REVOKED", false },
+ { "01004", "STRING DATA RIGHT TRUNCATION", false },
+ { "01P01", "DEPRECATED FEATURE", false },
+
+ { "02000", "NO DATA", false },
+ { "02001", "NO ADDITIONAL DYNAMIC RESULT SETS RETURNED", false },
+
+ { "03000", "SQL STATEMENT NOT YET COMPLETE", false },
+
+ { "08000", "CONNECTION EXCEPTION", false },
+ { "08003", "CONNECTION DOES NOT EXIST", false },
+ { "08006", "CONNECTION FAILURE", false },
+ { "08001", "SQLCLIENT UNABLE TO ESTABLISH SQLCONNECTION", false },
+ { "08004", "SQLSERVER REJECTED ESTABLISHMENT OF SQLCONNECTION", false },
+ { "08007", "TRANSACTION RESOLUTION UNKNOWN", false },
+ { "08P01", "PROTOCOL VIOLATION", false },
+
+ { "9000", "TRIGGERED ACTION EXCEPTION", false },
+
+ { "0A000", "FEATURE NOT SUPPORTED", false },
+
+ { "0B000", "INVALID TRANSACTION INITIATION", false },
+
+ { "0F000", "LOCATOR EXCEPTION", false },
+ { "0F001", "INVALID LOCATOR SPECIFICATION", false },
+
+ { "0L000", "INVALID GRANTOR", false },
+ { "0LP01", "INVALID GRANT OPERATION", false },
+
+ { "21000", "CARDINALITY VIOLATION", false },
+
+ { "22000", "DATA EXCEPTION", false },
+ { "2202E", "ARRAY SUBSCRIPT ERROR", false },
+ { "22021", "CHARACTER NOT IN REPERTOIRE", false },
+ { "22008", "DATETIME FIELD OVERFLOW", false },
+ { "22012", "DIVISION BY ZERO", false },
+ { "22005", "ERROR IN ASSIGNMENT", false },
+ { "2200B", "ESCAPE CHARACTER CONFLICT", false },
+ { "22022", "INDICATOR OVERFLOW", false },
+ { "22015", "INTERVAL FIELD OVERFLOW", false },
+ { "2201E", "INVALID ARGUMENT FOR LOGARITHM", false },
+ { "2201F", "INVALID ARGUMENT FOR POWER FUNCTION", false },
+ { "2201G", "INVALID ARGUMENT FOR WIDTH BUCKET FUNCTION", false },
+ { "22018", "INVALID CHARACTER VALUE FOR CAST", false },
+ { "22007", "INVALID DATETIME FORMAT", false },
+ { "22019", "INVALID ESCAPE CHARACTER", false },
+ { "2200D", "INVALID ESCAPE OCTET", false },
+ { "22025", "INVALID ESCAPE SEQUENCE", false },
+ { "22P06", "NONSTANDARD USE OF ESCAPE CHARACTER", false },
+ { "22010", "INVALID INDICATOR PARAMETER VALUE", false },
+ { "22020", "INVALID LIMIT VALUE", false },
+ { "22023", "INVALID PARAMETER VALUE", false },
+ { "2201B", "INVALID REGULAR EXPRESSION", false },
+ { "22009", "INVALID TIME ZONE DISPLACEMENT VALUE", false },
+ { "2200C", "INVALID USE OF ESCAPE CHARACTER", false },
+ { "2200G", "MOST SPECIFIC TYPE MISMATCH", false },
+ { "22004", "NULL VALUE NOT ALLOWED", false },
+ { "22002", "NULL VALUE NO INDICATOR PARAMETER", false },
+ { "22003", "NUMERIC VALUE OUT OF RANGE", false },
+ { "22026", "STRING DATA LENGTH MISMATCH", false },
+ { "22001", "STRING DATA RIGHT TRUNCATION", false },
+ { "22011", "SUBSTRING ERROR", false },
+ { "22027", "TRIM ERROR", false },
+ { "22024", "UNTERMINATED C STRING", false },
+ { "2200F", "ZERO LENGTH CHARACTER STRING", false },
+ { "22P01", "FLOATING POINT EXCEPTION", false },
+ { "22P02", "INVALID TEXT REPRESENTATION", false },
+ { "22P03", "INVALID BINARY REPRESENTATION", false },
+ { "22P04", "BAD COPY FILE FORMAT", false },
+ { "22P05", "UNTRANSLATABLE CHARACTER", false },
+
+ { "23000", "INTEGRITY CONSTRAINT VIOLATION", false },
+ { "23001", "RESTRICT VIOLATION", false },
+ { "23502", "NOT NULL VIOLATION", false },
+ { "23503", "FOREIGN KEY VIOLATION", false },
+ { "23514", "CHECK VIOLATION", false },
+
+ { "24000", "INVALID CURSOR STATE", false },
+
+ { "25000", "INVALID TRANSACTION STATE", false },
+ { "25001", "ACTIVE SQL TRANSACTION", false },
+ { "25002", "BRANCH TRANSACTION ALREADY ACTIVE", false },
+ { "25008", "HELD CURSOR REQUIRES SAME ISOLATION LEVEL", false },
+ { "25003", "INAPPROPRIATE ACCESS MODE FOR BRANCH TRANSACTION", false },
+ { "25004", "INAPPROPRIATE ISOLATION LEVEL FOR BRANCH TRANSACTION", false },
+ { "25005", "NO ACTIVE SQL TRANSACTION FOR BRANCH TRANSACTION", false },
+ { "25006", "READ ONLY SQL TRANSACTION", false },
+ { "25007", "SCHEMA AND DATA STATEMENT MIXING NOT SUPPORTED", false },
+ { "25P01", "NO ACTIVE SQL TRANSACTION", false },
+ { "25P02", "IN FAILED SQL TRANSACTION", false },
+
+ { "26000", "INVALID SQL STATEMENT NAME", false },
+
+ { "27000", "TRIGGERED DATA CHANGE VIOLATION", false },
+
+ { "28000", "INVALID AUTHORIZATION SPECIFICATION", false },
+
+ { "2B000", "DEPENDENT PRIVILEGE DESCRIPTORS STILL EXIST", false },
+ { "2BP01", "DEPENDENT OBJECTS STILL EXIST", false },
+
+ { "2D000", "INVALID TRANSACTION TERMINATION", false },
+
+ { "2F000", "SQL ROUTINE EXCEPTION", false },
+ { "2F005", "FUNCTION EXECUTED NO RETURN STATEMENT", false },
+ { "2F002", "MODIFYING SQL DATA NOT PERMITTED", false },
+ { "2F003", "PROHIBITED SQL STATEMENT ATTEMPTED", false },
+ { "2F004", "READING SQL DATA NOT PERMITTED", false },
+
+ { "34000", "INVALID CURSOR NAME", false },
+
+ { "38000", "EXTERNAL ROUTINE EXCEPTION", false },
+ { "38001", "CONTAINING SQL NOT PERMITTED", false },
+ { "38002", "MODIFYING SQL DATA NOT PERMITTED", false },
+ { "38003", "PROHIBITED SQL STATEMENT ATTEMPTED", false },
+ { "38004", "READING SQL DATA NOT PERMITTED", false },
+
+ { "39000", "EXTERNAL ROUTINE INVOCATION EXCEPTION", false },
+ { "39001", "INVALID SQLSTATE RETURNED", false },
+ { "39004", "NULL VALUE NOT ALLOWED", false },
+ { "39P01", "TRIGGER PROTOCOL VIOLATED", false },
+ { "39P02", "SRF PROTOCOL VIOLATED", false },
+
+ { "3B000", "SAVEPOINT EXCEPTION", false },
+ { "3B001", "INVALID SAVEPOINT SPECIFICATION", false },
+
+ { "3D000", "INVALID CATALOG NAME", false },
+ { "3F000", "INVALID SCHEMA NAME", false },
+
+ { "40000", "TRANSACTION ROLLBACK", false },
+ { "40002", "TRANSACTION INTEGRITY CONSTRAINT VIOLATION", false },
+ { "40001", "SERIALIZATION FAILURE", false },
+ { "40003", "STATEMENT COMPLETION UNKNOWN", false },
+ { "40P01", "DEADLOCK DETECTED", false },
+
+ { "44000", "WITH CHECK OPTION VIOLATION", false },
+
+ { "53000", "INSUFFICIENT RESOURCES", false },
+ { "53100", "DISK FULL", false },
+ { "53200", "OUT OF MEMORY", false },
+ { "53300", "TOO MANY CONNECTIONS", false },
+
+ { "54000", "PROGRAM LIMIT EXCEEDED", false },
+ { "54001", "STATEMENT TOO COMPLEX", false },
+ { "54011", "TOO MANY COLUMNS", false },
+ { "54023", "TOO MANY ARGUMENTS", false },
+
+ { "55000", "OBJECT NOT IN PREREQUISITE STATE", false },
+ { "55006", "OBJECT IN USE", false },
+ { "55P02", "CANT CHANGE RUNTIME PARAM", false },
+ { "55P03", "LOCK NOT AVAILABLE", false },
+
+ { "57000", "OPERATOR INTERVENTION", true },
+
+ /*
+ * This is really 'statement_timeout' or the error which is returned when
+ * 'statement_timeout' is hit.
+ *
+ * It's unlikely that this has been caused by a connection failure, and
+ * most likely to have been caused by a long running query.
+ *
+ * If the query is persistently long running then the database/query should
+ * be optimised, or 'statement_timeout' should be increased.
+ *
+ * Forcing a reconnect here only eats more resources on the DB so we will
+ * no longer do so as of 3.0.4.
+ */
+ { "57014", "QUERY CANCELED", false },
+ { "57P01", "ADMIN SHUTDOWN", true },
+ { "57P02", "CRASH SHUTDOWN", true },
+ { "57P03", "CANNOT CONNECT NOW", true },
+
+ { "58030", "IO ERROR", true },
+ { "58P01", "UNDEFINED FILE", true },
+ { "58P02", "DUPLICATE FILE", true },
+
+ { "F0000", "CONFIG FILE ERROR", true },
+ { "F0001", "LOCK FILE EXISTS", true },
+
+ { "P0000", "PLPGSQL ERROR", false },
+ { "P0001", "RAISE EXCEPTION", false },
+
+ { "42000", "SYNTAX ERROR OR ACCESS RULE VIOLATION", false },
+ { "42601", "SYNTAX ERROR", false },
+ { "42501", "INSUFFICIENT PRIVILEGE", false },
+ { "42846", "CANNOT COERCE", false },
+ { "42803", "GROUPING ERROR", false },
+ { "42830", "INVALID FOREIGN KEY", false },
+ { "42602", "INVALID NAME", false },
+ { "42622", "NAME TOO LONG", false },
+ { "42939", "RESERVED NAME", false },
+ { "42804", "DATATYPE MISMATCH", false },
+ { "42P18", "INDETERMINATE DATATYPE", false },
+ { "42809", "WRONG OBJECT TYPE", false },
+ { "42703", "UNDEFINED COLUMN", false },
+ { "42883", "UNDEFINED FUNCTION", false },
+ { "42P01", "UNDEFINED TABLE", false },
+ { "42P02", "UNDEFINED PARAMETER", false },
+ { "42704", "UNDEFINED OBJECT", false },
+ { "42701", "DUPLICATE COLUMN", false },
+ { "42P03", "DUPLICATE CURSOR", false },
+ { "42P04", "DUPLICATE DATABASE", false },
+ { "42723", "DUPLICATE FUNCTION", false },
+ { "42P05", "DUPLICATE PREPARED STATEMENT", false },
+ { "42P06", "DUPLICATE SCHEMA", false },
+ { "42P07", "DUPLICATE TABLE", false },
+ { "42712", "DUPLICATE ALIAS", false },
+ { "42710", "DUPLICATE OBJECT", false },
+ { "42702", "AMBIGUOUS COLUMN", false },
+ { "42725", "AMBIGUOUS FUNCTION", false },
+ { "42P08", "AMBIGUOUS PARAMETER", false },
+ { "42P09", "AMBIGUOUS ALIAS", false },
+ { "42P10", "INVALID COLUMN REFERENCE", false },
+ { "42611", "INVALID COLUMN DEFINITION", false },
+ { "42P11", "INVALID CURSOR DEFINITION", false },
+ { "42P12", "INVALID DATABASE DEFINITION", false },
+ { "42P13", "INVALID FUNCTION DEFINITION", false },
+ { "42P14", "INVALID PREPARED STATEMENT DEFINITION", false },
+ { "42P15", "INVALID SCHEMA DEFINITION", false },
+ { "42P16", "INVALID TABLE DEFINITION", false },
+ { "42P17", "INVALID OBJECT DEFINITION", false },
+
+ { "XX000", "INTERNAL ERROR", false },
+ { "XX001", "DATA CORRUPTED", false },
+ { "XX002", "INDEX CORRUPTED", false },
{ NULL, NULL, 0 }
};
/* config.h.in. Generated from configure.ac by autoheader. */
-/* Define if the SQLite library has v2 API functions */
-#undef HAVE_SQLITE_V2_API
+/* Define to 1 if you have the `sqlite3_create_function_v2' function. */
+#undef HAVE_SQLITE3_CREATE_FUNCTION_V2
+
+/* Define to 1 if you have the `sqlite3_errstr' function. */
+#undef HAVE_SQLITE3_ERRSTR
+
+/* Define to 1 if you have the `sqlite3_extended_result_codes' function. */
+#undef HAVE_SQLITE3_EXTENDED_RESULT_CODES
+
+/* Define to 1 if the system has the type `sqlite3_int64'. */
+#undef HAVE_SQLITE3_INT64
+
+/* Define to 1 if you have the `sqlite3_open_v2' function. */
+#undef HAVE_SQLITE3_OPEN_V2
+
+/* Define to 1 if you have the `sqlite3_prepare_v2' function. */
+#undef HAVE_SQLITE3_PREPARE_V2
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-sqlite-include-dir=DIR
- Directory where the sqlite includes may be found
+ Directory where the sqlite includes may be found
--with-sqlite-lib-dir=DIR
- Directory where the sqlite libraries may be found
+ Directory where the sqlite libraries may be found
--with-sqlite-dir=DIR Base directory where sqlite is installed
Some influential environment variables:
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
as_fn_set_status $ac_retval
} # ac_fn_c_try_link
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=no"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ eval "$3=yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_type
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
if test x$with_rlm_sql_sqlite != xno; then
- sqlite_include_dir=
+ sqlite_include_dir=
# Check whether --with-sqlite-include-dir was given.
if test "${with_sqlite_include_dir+set}" = set; then :
fi
- sqlite_lib_dir=
+ sqlite_lib_dir=
# Check whether --with-sqlite-lib-dir was given.
if test "${with_sqlite_lib_dir+set}" = set; then :
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
- smart_try_dir="$sqlite_lib_dir"
+ smart_try_dir="$sqlite_lib_dir"
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lsqlite3"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lsqlite3"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libsqlite3${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libsqlite3.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
SMART_LIBS="$smart_lib $SMART_LIBS"
fi
+ LDFLAGS="$SMART_LIBS"
if test "x$ac_cv_lib_sqlite3_sqlite3_open" != "xyes"
then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Sqlite libraries not found. Use --with-sqlite-lib-dir=<path>." >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Sqlite libraries not found. Use --with-sqlite-lib-dir=<path>." >&5
$as_echo "$as_me: WARNING: Sqlite libraries not found. Use --with-sqlite-lib-dir=<path>." >&2;}
- fail="$fail libsqlite3"
+ fail="$fail libsqlite3"
else
-
-
-sm_lib_safe=`echo "sqlite3" | sed 'y%./+-%__p_%'`
-sm_func_safe=`echo "sqlite3_open_v2" | sed 'y%./+-%__p_%'`
-
-old_LIBS="$LIBS"
-smart_lib=
-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 sqlite3_open_v2 in -lsqlite3 in $try" >&5
-$as_echo_n "checking for sqlite3_open_v2 in -lsqlite3 in $try... " >&6; }
- LIBS="-L$try -lsqlite3 $old_LIBS -Wl,-rpath,$try"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-extern char sqlite3_open_v2();
-int
-main ()
-{
-sqlite3_open_v2()
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-
- smart_lib="-L$try -lsqlite3 -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"
-fi
-
-if test "x$smart_lib" = "x"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqlite3_open_v2 in -lsqlite3" >&5
-$as_echo_n "checking for sqlite3_open_v2 in -lsqlite3... " >&6; }
- LIBS="-lsqlite3 $old_LIBS"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-extern char sqlite3_open_v2();
-int
-main ()
-{
-sqlite3_open_v2()
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-
- smart_lib="-lsqlite3"
- { $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=libsqlite3${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=libsqlite3.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 sqlite3_open_v2 in -lsqlite3 in $try" >&5
-$as_echo_n "checking for sqlite3_open_v2 in -lsqlite3 in $try... " >&6; }
- LIBS="-L$try -lsqlite3 $old_LIBS -Wl,-rpath,$try"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-extern char sqlite3_open_v2();
-int
-main ()
-{
-sqlite3_open_v2()
- ;
- return 0;
-}
+ for ac_func in \
+ sqlite3_prepare_v2 \
+ sqlite3_open_v2 \
+ sqlite3_create_function_v2 \
+ sqlite3_errstr \
+ sqlite3_extended_result_codes \
+
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-L$try -lsqlite3 -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"
-fi
-
-if test "x$smart_lib" != "x"; then
- eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
- LIBS="$smart_lib $old_LIBS"
- SMART_LIBS="$smart_lib $SMART_LIBS"
fi
+done
- if test "x$ac_cv_lib_sqlite3_sqlite3_open_v2" == "xyes"
- then
-
-$as_echo "#define HAVE_SQLITE_V2_API 1" >>confdefs.h
-
- fi
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=sqlite3.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
fi
if test "x$ac_cv_header_sqlite3_h" != "xyes"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Sqlite headers not found. Use --with-sqlite-include-dir=<path>." >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Sqlite headers not found. Use --with-sqlite-include-dir=<path>." >&5
$as_echo "$as_me: WARNING: Sqlite headers not found. Use --with-sqlite-include-dir=<path>." >&2;}
- fail="$fail sqlite.h"
+ fail="$fail sqlite.h"
fi
+ CFLAGS="$SMART_CPPFLAGS"
+ ac_fn_c_check_type "$LINENO" "sqlite3_int64" "ac_cv_type_sqlite3_int64" "#include <sqlite3.h>
+"
+if test "x$ac_cv_type_sqlite3_int64" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_SQLITE3_INT64 1
+_ACEOF
+
+
+fi
+
targetname=rlm_sql_sqlite
else
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
--header=FILE[:TEMPLATE]
- instantiate the configuration header FILE
+ instantiate the configuration header FILE
Configuration files:
$config_files
dnl try to link to libsqlite3
smart_try_dir="$sqlite_lib_dir"
FR_SMART_CHECK_LIB(sqlite3, sqlite3_open)
+ dnl # Ensure we use the library we just found the rest of the checks
+ LDFLAGS="$SMART_LIBS"
if test "x$ac_cv_lib_sqlite3_sqlite3_open" != "xyes"
then
- AC_MSG_WARN([Sqlite libraries not found. Use --with-sqlite-lib-dir=<path>.])
- fail="$fail libsqlite3"
+ AC_MSG_WARN([Sqlite libraries not found. Use --with-sqlite-lib-dir=<path>.])
+ fail="$fail libsqlite3"
else
- FR_SMART_CHECK_LIB(sqlite3, sqlite3_open_v2)
- if test "x$ac_cv_lib_sqlite3_sqlite3_open_v2" == "xyes"
- then
- AC_DEFINE(HAVE_SQLITE_V2_API, [1], [Define if the SQLite library has v2 API functions])
- fi
+ dnl # Add any v2 variants here
+ AC_CHECK_FUNCS(\
+ sqlite3_prepare_v2 \
+ sqlite3_open_v2 \
+ sqlite3_create_function_v2 \
+ sqlite3_errstr \
+ sqlite3_extended_result_codes \
+ )
fi
dnl ############################################################
smart_try_dir="$sqlite_include_dir"
FR_SMART_CHECK_INCLUDE(sqlite3.h)
if test "x$ac_cv_header_sqlite3_h" != "xyes"; then
- AC_MSG_WARN([Sqlite headers not found. Use --with-sqlite-include-dir=<path>.])
- fail="$fail sqlite.h"
+ AC_MSG_WARN([Sqlite headers not found. Use --with-sqlite-include-dir=<path>.])
+ fail="$fail sqlite.h"
fi
+ CFLAGS="$SMART_CPPFLAGS"
+ AC_CHECK_TYPES([sqlite3_int64], [], [], [[#include <sqlite3.h>]])
targetname=modname
else
# define SQLITE_OPEN_NOMUTEX 0
#endif
+#ifndef HAVE_SQLITE3_INT64
+typedef sqlite3_int64 sqlite_int64
+#endif
+
typedef struct rlm_sql_sqlite_conn {
sqlite3 *db;
sqlite3_stmt *statement;
} rlm_sql_sqlite_config_t;
static const CONF_PARSER driver_config[] = {
- {"filename", PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED,
- offsetof(rlm_sql_sqlite_config_t, filename), NULL, NULL},
- {"bootstrap", PW_TYPE_FILE_INPUT,
- offsetof(rlm_sql_sqlite_config_t, bootstrap), NULL, NULL},
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED, rlm_sql_sqlite_config_t, filename), NULL },
+ { "bootstrap", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_sql_sqlite_config_t, bootstrap), NULL },
{NULL, -1, 0, NULL, NULL}
};
}
}
-#ifdef HAVE_SQLITE_V2_API
+#ifdef HAVE_SQLITE3_OPEN_V2
static int sql_loadfile(TALLOC_CTX *ctx, sqlite3 *db, char const *filename)
{
ssize_t len;
f = fopen(filename, "r");
if (!f) {
ERROR("rlm_sql_sqlite: Failed opening SQL file \"%s\": %s", filename,
- strerror(errno));
+ fr_syserror(errno));
return -1;
}
if (fstat(fileno(f), &finfo) < 0) {
ERROR("rlm_sql_sqlite: Failed stating SQL file \"%s\": %s", filename,
- strerror(errno));
+ fr_syserror(errno));
fclose(f);
if (!len) {
if (ferror(f)) {
- ERROR("rlm_sql_sqlite: Error reading SQL file: %s", strerror(errno));
+ ERROR("rlm_sql_sqlite: Error reading SQL file: %s", fr_syserror(errno));
fclose(f);
talloc_free(buffer);
*q = '\0';
+#ifdef HAVE_SQLITE3_PREPARE_V2
(void) sqlite3_prepare_v2(db, s, len, &statement, &z_tail);
+#else
+ (void) sqlite3_prepare(db, s, len, &>statement, &z_tail);
+#endif
if (sql_check_error(db)) {
talloc_free(buffer);
return -1;
static int mod_instantiate(CONF_SECTION *conf, rlm_sql_config_t *config)
{
+ bool exists;
rlm_sql_sqlite_config_t *driver;
- int exists;
+ struct stat buf;
if (sqlite3_libversion_number() != SQLITE_VERSION_NUMBER) {
DEBUG2("rlm_sql_sqlite: SQLite library version (%s) is different from the version the server was "
}
MEM(driver = config->driver = talloc_zero(config, rlm_sql_sqlite_config_t));
-
if (cf_section_parse(conf, driver, driver_config) < 0) {
return -1;
}
INFO("rlm_sql_sqlite: SQLite library version: %s", sqlite3_libversion());
if (!driver->filename) {
- MEM(driver->filename = talloc_asprintf(driver, "%s/%s", radius_dir, config->sql_db));
+ MEM(driver->filename = talloc_typed_asprintf(driver, "%s/%s", get_radius_dir(), config->sql_db));
}
- exists = rad_file_exists(driver->filename);
- if (exists < 0) {
- ERROR("rlm_sql_sqlite: Database exists, but couldn't be opened: %s", strerror(errno));
-
+ if (stat(driver->filename, &buf) == 0) {
+ exists = true;
+ } else if (errno == ENOENT) {
+ exists = false;
+ } else {
+ ERROR("rlm_sql_sqlite: Database exists, but couldn't be opened: %s", fr_syserror(errno));
return -1;
}
if (driver->bootstrap && !exists) {
-#ifdef HAVE_SQLITE_V2_API
+# ifdef HAVE_SQLITE3_OPEN_V2
int status;
int ret;
char *p;
buff = talloc_array(conf, char, len);
strlcpy(buff, driver->filename, len);
} else {
- MEM(buff = talloc_strdup(conf, driver->filename));
+ MEM(buff = talloc_typed_strdup(conf, driver->filename));
}
- if (rad_mkdir(buff, 0700) < 0) {
- ERROR("rlm_sql_sqlite: Failed creating directory for SQLite database");
-
- talloc_free(buff);
+ ret = rad_mkdir(buff, 0700);
+ talloc_free(buff);
+ if (ret < 0) {
+ ERROR("rlm_sql_sqlite: Failed creating directory for SQLite database: %s", fr_syserror(errno));
return -1;
- }
-
- talloc_free(buff);
+ };
status = sqlite3_open_v2(driver->filename, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
if (!db) {
- ERROR("rlm_sql_sqlite: Failed creating opening/creating SQLite database, error "
- "code (%u)", status);
+# ifdef HAVE_SQLITE3_ERRSTR
+ ERROR("rlm_sql_sqlite: Failed creating opening/creating SQLite database: %s",
+ sqlite3_errstr(status));
+# else
+ ERROR("rlm_sql_sqlite: Failed creating opening/creating SQLite database, got code (%i)",
+ status);
+# endif
goto unlink;
}
ret = sql_loadfile(conf, db, driver->bootstrap);
status = sqlite3_close(db);
if (status != SQLITE_OK) {
- ERROR("rlm_sql_sqlite: Error closing SQLite handle, error code (%u)", status);
+ /*
+ * Safer to use sqlite3_errstr here, just in case the handle is in a weird state
+ */
+# ifdef HAVE_SQLITE3_ERRSTR
+ ERROR("rlm_sql_sqlite: Error closing SQLite handle: %s", sqlite3_errstr(status));
+# else
+ ERROR("rlm_sql_sqlite: Error closing SQLite handle, got code (%i)", status);
+# endif
+
goto unlink;
}
if (ret < 0) {
- unlink:
- if (unlink(driver->filename) < 0) {
+ unlink:
+ if ((unlink(driver->filename) < 0) && (errno != ENOENT)) {
ERROR("rlm_sql_sqlite: Error removing partially initialised database: %s",
- strerror(errno));
+ fr_syserror(errno));
}
return -1;
}
#else
- WDEBUG("rlm_sql_sqlite: sqlite3_open_v2() not available, cannot bootstrap database. "
+ WARN("rlm_sql_sqlite: sqlite3_open_v2() not available, cannot bootstrap database. "
"Upgrade to SQLite >= 3.5.1 if you need this functionality");
#endif
}
if (conn->db) {
status = sqlite3_close(conn->db);
if (status != SQLITE_OK) {
- WDEBUG("rlm_sql_sqlite: Got SQLite error code (%u) when closing socket", status);
+ WARN("rlm_sql_sqlite: Got SQLite error code (%u) when closing socket", status);
}
}
talloc_set_destructor((void *) conn, sql_socket_destructor);
INFO("rlm_sql_sqlite: Opening SQLite database \"%s\"", driver->filename);
-
-#ifdef HAVE_SQLITE_V2_API
+#ifdef HAVE_SQLITE3_OPEN_V2
status = sqlite3_open_v2(driver->filename, &(conn->db), SQLITE_OPEN_READWRITE | SQLITE_OPEN_NOMUTEX, NULL);
#else
status = sqlite3_open(driver->filename, &(conn->db));
#endif
if (!conn->db) {
- ERROR("rlm_sql_sqlite: Failed creating opening/creating SQLite database error code (%u)",
- status);
+#ifdef HAVE_SQLITE3_ERRSTR
+ ERROR("rlm_sql_sqlite: Failed creating opening/creating SQLite: %s", sqlite3_errstr(status));
+#else
+ ERROR("rlm_sql_sqlite: Failed creating opening/creating SQLite database error code (%i)",
+ status);
+#endif
return -1;
}
/*
* Enable extended return codes for extra debugging info.
*/
- status = sqlite3_extended_result_codes(conn->db, 1);
-
+#ifdef HAVE_SQLITE3_EXTENDED_RESULT_CODES
+ (void) sqlite3_extended_result_codes(conn->db, 1);
+#endif
if (sql_check_error(conn->db)) {
return -1;
}
-#ifdef HAVE_SQLITE_V2_API
+#ifdef HAVE_SQLITE3_CREATE_FUNCTION_V2
status = sqlite3_create_function_v2(conn->db, "GREATEST", -1, SQLITE_ANY, NULL,
_sql_greatest, NULL, NULL, NULL);
#else
rlm_sql_sqlite_conn_t *conn = handle->conn;
char const *z_tail;
-#ifdef HAVE_SQLITE_V2_API
+#ifdef HAVE_SQLITE3_PREPARE_V2
(void) sqlite3_prepare_v2(conn->db, query, strlen(query), &conn->statement, &z_tail);
#else
(void) sqlite3_prepare(conn->db, query, strlen(query), &conn->statement, &z_tail);
rlm_sql_sqlite_conn_t *conn = handle->conn;
char const *z_tail;
-#ifdef HAVE_SQLITE_V2_API
+#ifdef HAVE_SQLITE3_PREPARE_V2
status = sqlite3_prepare_v2(conn->db, query, strlen(query), &conn->statement, &z_tail);
#else
status = sqlite3_prepare(conn->db, query, strlen(query), &conn->statement, &z_tail);
for (i = 0; i < conn->col_count; i++) {
switch (sqlite3_column_type(conn->statement, i)) {
case SQLITE_INTEGER:
- MEM(row[i] = talloc_asprintf(row, "%d", sqlite3_column_int(conn->statement, i)));
+ MEM(row[i] = talloc_typed_asprintf(row, "%d", sqlite3_column_int(conn->statement, i)));
break;
case SQLITE_FLOAT:
- MEM(row[i] = talloc_asprintf(row, "%f", sqlite3_column_double(conn->statement, i)));
+ MEM(row[i] = talloc_typed_asprintf(row, "%f", sqlite3_column_double(conn->statement, i)));
break;
case SQLITE_TEXT:
p = (char const *) sqlite3_column_text(conn->statement, i);
if (p) {
- MEM(row[i] = talloc_strdup(row, p));
+ MEM(row[i] = talloc_typed_strdup(row, p));
}
}
break;
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-unixodbc-include-dir=DIR
- Directory where the unixODBC includes may be found
+ Directory where the unixODBC includes may be found
--with-unixodbc-lib-dir=DIR
- Directory where the unixODBC libraries may be found
+ Directory where the unixODBC libraries may be found
--with-unixodbc-dir=DIR Base directory where unixODBC is installed
Some influential environment variables:
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lodbc"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lodbc"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libodbc${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libodbc.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=sql.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
} rlm_sql_unixodbc_conn_t;
+USES_APPLE_DEPRECATED_API
#include <sql.h>
#include <sqlext.h>
if (sql_state(err_handle, handle, config)) {
ERROR("rlm_sql_unixodbc: Can't allocate connection handle");
return -1;
- }
+ }
/* 3. Connect to the datasource */
{
if ((state = sql_state(err_handle, handle, config))) {
if(state == RLM_SQL_RECONNECT) {
- DEBUG("rlm_sql_unixodbc: rlm_sql will attempt to reconnect");
- }
+ DEBUG("rlm_sql_unixodbc: rlm_sql will attempt to reconnect");
+ }
return state;
}
default:
ERROR("rlm_sql_unixodbc: %s %s", state, error);
res = -1;
- break;
+ break;
}
}
#include "rlm_sql.h"
static const CONF_PARSER acct_section_config[] = {
- {"reference", PW_TYPE_STRING_PTR,
- offsetof(sql_acct_section_t, reference), NULL, ".query"},
- {"logfile", PW_TYPE_STRING_PTR,
- offsetof(sql_acct_section_t, logfile), NULL, NULL},
+ { "reference", FR_CONF_OFFSET(PW_TYPE_STRING, sql_acct_section_t, reference), ".query" },
+ { "logfile", FR_CONF_OFFSET(PW_TYPE_STRING, sql_acct_section_t, logfile), NULL },
{NULL, -1, 0, NULL, NULL}
};
static const CONF_PARSER module_config[] = {
- {"driver", PW_TYPE_STRING_PTR,
- offsetof(rlm_sql_config_t,sql_driver_name), NULL, "rlm_sql_null"},
- {"server", PW_TYPE_STRING_PTR,
- offsetof(rlm_sql_config_t,sql_server), NULL, "localhost"},
- {"port", PW_TYPE_STRING_PTR,
- offsetof(rlm_sql_config_t,sql_port), NULL, ""},
- {"login", PW_TYPE_STRING_PTR,
- offsetof(rlm_sql_config_t,sql_login), NULL, ""},
- {"password", PW_TYPE_STRING_PTR,
- offsetof(rlm_sql_config_t,sql_password), NULL, ""},
- {"radius_db", PW_TYPE_STRING_PTR,
- offsetof(rlm_sql_config_t,sql_db), NULL, "radius"},
- {"read_groups", PW_TYPE_BOOLEAN,
- offsetof(rlm_sql_config_t,read_groups), NULL, "yes"},
- {"readclients", PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED,
- offsetof(rlm_sql_config_t,do_clients), NULL, NULL},
- {"read_clients", PW_TYPE_BOOLEAN,
- offsetof(rlm_sql_config_t,do_clients), NULL, "no"},
- {"deletestalesessions", PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED,
- offsetof(rlm_sql_config_t,deletestalesessions), NULL, NULL},
- {"delete_stale_sessions", PW_TYPE_BOOLEAN,
- offsetof(rlm_sql_config_t,deletestalesessions), NULL, "yes"},
- {"sql_user_name", PW_TYPE_STRING_PTR,
- offsetof(rlm_sql_config_t,query_user), NULL, ""},
- {"logfile", PW_TYPE_STRING_PTR,
- offsetof(rlm_sql_config_t,logfile), NULL, NULL},
- {"default_user_profile", PW_TYPE_STRING_PTR,
- offsetof(rlm_sql_config_t,default_profile), NULL, ""},
- {"nas_query", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_sql_config_t,client_query), NULL, NULL},
- {"client_query", PW_TYPE_STRING_PTR,
- offsetof(rlm_sql_config_t,client_query), NULL,
- "SELECT id,nasname,shortname,type,secret FROM nas"},
- {"authorize_check_query", PW_TYPE_STRING_PTR,
- offsetof(rlm_sql_config_t,authorize_check_query), NULL, ""},
- {"authorize_reply_query", PW_TYPE_STRING_PTR,
- offsetof(rlm_sql_config_t,authorize_reply_query), NULL, NULL},
- {"authorize_group_check_query", PW_TYPE_STRING_PTR,
- offsetof(rlm_sql_config_t,authorize_group_check_query), NULL, ""},
- {"authorize_group_reply_query", PW_TYPE_STRING_PTR,
- offsetof(rlm_sql_config_t,authorize_group_reply_query), NULL, ""},
- {"group_membership_query", PW_TYPE_STRING_PTR,
- offsetof(rlm_sql_config_t,groupmemb_query), NULL, NULL},
+ { "driver", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, sql_driver_name), "rlm_sql_null" },
+ { "server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, sql_server), "localhost" },
+ { "port", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, sql_port), "" },
+ { "login", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, sql_login), "" },
+ { "password", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, rlm_sql_config_t, sql_password), "" },
+ { "radius_db", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, sql_db), "radius" },
+ { "read_groups", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sql_config_t, read_groups), "yes" },
+ { "readclients", FR_CONF_OFFSET(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, rlm_sql_config_t, do_clients), NULL },
+ { "read_clients", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sql_config_t, do_clients), "no" },
+ { "deletestalesessions", FR_CONF_OFFSET(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, rlm_sql_config_t, deletestalesessions), NULL },
+ { "delete_stale_sessions", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sql_config_t, deletestalesessions), "yes" },
+ { "sql_user_name", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, query_user), "" },
+ { "logfile", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, logfile), NULL },
+ { "default_user_profile", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, default_profile), "" },
+ { "nas_query", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sql_config_t, client_query), NULL },
+ { "client_query", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, client_query), "SELECT id,nasname,shortname,type,secret FROM nas" },
+ { "authorize_check_query", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, authorize_check_query), "" },
+ { "open_query", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, open_query), NULL },
+ { "authorize_reply_query", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, authorize_reply_query), NULL },
+ { "authorize_group_check_query", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, authorize_group_check_query), "" },
+ { "authorize_group_reply_query", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, authorize_group_reply_query), "" },
+ { "group_membership_query", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, groupmemb_query), NULL },
#ifdef WITH_SESSION_MGMT
- {"simul_count_query", PW_TYPE_STRING_PTR,
- offsetof(rlm_sql_config_t,simul_count_query), NULL, ""},
- {"simul_verify_query", PW_TYPE_STRING_PTR,
- offsetof(rlm_sql_config_t,simul_verify_query), NULL, ""},
+ { "simul_count_query", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, simul_count_query), "" },
+ { "simul_verify_query", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, simul_verify_query), "" },
#endif
- {"safe-characters", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_sql_config_t,allowed_chars), NULL, NULL},
- {"safe_characters", PW_TYPE_STRING_PTR,
- offsetof(rlm_sql_config_t,allowed_chars), NULL,
- "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"},
+ { "safe-characters", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sql_config_t, allowed_chars), NULL },
+ { "safe_characters", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, allowed_chars), "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /" },
/*
* This only works for a few drivers.
*/
- {"query_timeout", PW_TYPE_INTEGER,
- offsetof(rlm_sql_config_t,query_timeout), NULL, NULL},
+ { "query_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_sql_config_t, query_timeout), NULL },
{NULL, -1, 0, NULL, NULL}
};
int numaffected;
char buffer[21]; /* 64bit max is 20 decimal chars + null byte */
- if (rlm_sql_query(&handle, inst, query)) {
+ if (rlm_sql_query(&handle, inst, query) != RLM_SQL_OK) {
+ char const *error = (inst->module->sql_error)(handle, inst->config);
+ REDEBUG("SQL query failed: %s", error);
+
+ ret = -1;
goto finish;
}
goto finish;
} /* else it's a SELECT statement */
- if (rlm_sql_select_query(&handle, inst, query)){
+ if (rlm_sql_select_query(&handle, inst, query) != RLM_SQL_OK){
+ char const *error = (inst->module->sql_error)(handle, inst->config);
+ REDEBUG("SQL query failed: %s", error);
ret = -1;
goto finish;
ret = rlm_sql_fetch_row(&handle, inst);
if (ret) {
- RDEBUG("SQL query failed");
+ REDEBUG("SQL query failed");
(inst->module->sql_finish_select_query)(handle, inst->config);
ret = -1;
}
if (!row[0]){
- RDEBUG("Null value in first column");
+ RDEBUG("NULL value in first column of result");
(inst->module->sql_finish_select_query)(handle, inst->config);
ret = -1;
strlcpy(out, row[0], freespace);
ret = len;
- RDEBUG("sql_xlat finished");
-
(inst->module->sql_finish_select_query)(handle, inst->config);
- finish:
+finish:
sql_release_socket(inst, handle);
return ret;
return -1;
}
- if (rlm_sql_select_query(&handle, inst, inst->config->client_query)){
+ if (rlm_sql_select_query(&handle, inst, inst->config->client_query) != RLM_SQL_OK){
return -1;
}
- while((rlm_sql_fetch_row(&handle, inst) == 0) && (row = handle->row)) {
+ while ((rlm_sql_fetch_row(&handle, inst) == 0) && (row = handle->row)) {
char *server = NULL;
i++;
char const *sqluser;
ssize_t len;
+ rad_assert(request->packet != NULL);
+
if (username != NULL) {
sqluser = username;
} else if (inst->config->query_user[0] != '\0') {
pairstrsteal(vp, expanded);
RDEBUG2("SQL-User-Name set to '%s'", vp->vp_strvalue);
vp->op = T_OP_SET;
- pairmove(request, &request->packet->vps, &vp); /* needs to be pair move else op is not respected */
+ radius_pairmove(request, &request->packet->vps, vp, false); /* needs to be pair move else op is not respected */
return 0;
}
-static int sql_get_grouplist(rlm_sql_t *inst, rlm_sql_handle_t *handle, REQUEST *request,
+static int sql_get_grouplist(rlm_sql_t *inst, rlm_sql_handle_t **handle, REQUEST *request,
rlm_sql_grouplist_t **phead)
{
char *expanded = NULL;
return -1;
}
- ret = rlm_sql_select_query(&handle, inst, expanded);
+ ret = rlm_sql_select_query(handle, inst, expanded);
talloc_free(expanded);
- if (ret < 0) {
+ if (ret != RLM_SQL_OK) {
return -1;
}
- while (rlm_sql_fetch_row(&handle, inst) == 0) {
- row = handle->row;
+ while (rlm_sql_fetch_row(handle, inst) == 0) {
+ row = (*handle)->row;
if (!row)
break;
+
if (!row[0]){
RDEBUG("row[0] returned NULL");
- (inst->module->sql_finish_select_query)(handle, inst->config);
+ (inst->module->sql_finish_select_query)(*handle, inst->config);
talloc_free(entry);
return -1;
}
if (!*phead) {
- *phead = talloc_zero(handle, rlm_sql_grouplist_t);
+ *phead = talloc_zero(*handle, rlm_sql_grouplist_t);
entry = *phead;
} else {
entry->next = talloc_zero(*phead, rlm_sql_grouplist_t);
entry = entry->next;
}
entry->next = NULL;
- entry->name = talloc_strdup(entry, row[0]);
+ entry->name = talloc_typed_strdup(entry, row[0]);
+
+ num_groups++;
}
- (inst->module->sql_finish_select_query)(handle, inst->config);
+ (inst->module->sql_finish_select_query)(*handle, inst->config);
return num_groups;
}
* username will then be checked with the passed check string.
*/
-static int sql_groupcmp(void *instance, REQUEST *request, UNUSED VALUE_PAIR *request_vp, VALUE_PAIR *check,
- UNUSED VALUE_PAIR *check_pairs, UNUSED VALUE_PAIR **reply_pairs)
+static int CC_HINT(nonnull (1 ,2, 4)) sql_groupcmp(void *instance, REQUEST *request, UNUSED VALUE_PAIR *request_vp,
+ VALUE_PAIR *check, UNUSED VALUE_PAIR *check_pairs,
+ UNUSED VALUE_PAIR **reply_pairs)
{
rlm_sql_handle_t *handle;
rlm_sql_t *inst = instance;
rlm_sql_grouplist_t *head, *entry;
RDEBUG("sql_groupcmp");
- if (!check || !check->length){
+
+ if (check->length == 0){
RDEBUG("sql_groupcmp: Illegal group name");
return 1;
}
- if (!request){
- RDEBUG("sql_groupcmp: NULL request");
- return 1;
- }
+
/*
* Set, escape, and check the user attr here
*/
/*
* Get the list of groups this user is a member of
*/
- if (sql_get_grouplist(inst, handle, request, &head) < 0) {
+ if (sql_get_grouplist(inst, &handle, request, &head) < 0) {
REDEBUG("Error getting group membership");
sql_release_socket(inst, handle);
return 1;
/* Free the grouplist */
talloc_free(head);
- sql_release_socket(inst,handle);
+ sql_release_socket(inst, handle);
- RDEBUG("sql_groupcmp finished: User is NOT a member of group %s",
- check->vp_strvalue);
+ RDEBUG("sql_groupcmp finished: User is NOT a member of group %s", check->vp_strvalue);
return 1;
}
-static rlm_rcode_t rlm_sql_process_groups(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t *handle,
+static rlm_rcode_t rlm_sql_process_groups(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle,
bool *dofallthrough)
{
rlm_rcode_t rcode = RLM_MODULE_NOOP;
char *expanded = NULL;
int rows;
+ rad_assert(request->packet != NULL);
+
/*
* Get the list of groups this user is a member of
*/
return RLM_MODULE_FAIL;
}
if (rows == 0) {
+ RDEBUG2("User not found in any groups");
rcode = RLM_MODULE_NOTFOUND;
goto finish;
}
goto finish;
}
- rows = sql_getvpdata(inst, &handle, request, &check_tmp, expanded);
+ rows = sql_getvpdata(inst, handle, request, &check_tmp, expanded);
TALLOC_FREE(expanded);
if (rows < 0) {
REDEBUG("Error retrieving check pairs for group %s", entry->name);
RDEBUG2("Group \"%s\" check items matched", entry->name);
rcode = RLM_MODULE_OK;
- radius_xlat_move(request, &request->config_items, &check_tmp);
+ radius_pairmove(request, &request->config_items, check_tmp, true);
check_tmp = NULL;
}
goto finish;
}
- rows = sql_getvpdata(inst, &handle, request->reply, &reply_tmp, expanded);
+ rows = sql_getvpdata(inst, handle, request->reply, &reply_tmp, expanded);
TALLOC_FREE(expanded);
if (rows < 0) {
REDEBUG("Error retrieving reply pairs for group %s", entry->name);
RDEBUG2("Group \"%s\" reply items processed", entry->name);
rcode = RLM_MODULE_OK;
- radius_xlat_move(request, &request->reply->vps, &reply_tmp);
+ radius_pairmove(request, &request->reply->vps, reply_tmp, true);
reply_tmp = NULL;
}
}
static int parse_sub_section(CONF_SECTION *parent,
- rlm_sql_t *inst,
- sql_acct_section_t **config,
- rlm_components_t comp)
+ rlm_sql_t *inst,
+ sql_acct_section_t **config,
+ rlm_components_t comp)
{
CONF_SECTION *cs;
inst->config->xlat_name = cf_section_name1(conf);
} else {
char *group_name;
- DICT_ATTR const *dattr;
+ DICT_ATTR const *da;
ATTR_FLAGS flags;
/*
* Allocate room for <instance>-SQL-Group
*/
- group_name = talloc_asprintf(inst, "%s-SQL-Group", inst->config->xlat_name);
+ group_name = talloc_typed_asprintf(inst, "%s-SQL-Group", inst->config->xlat_name);
DEBUG("rlm_sql (%s): Creating new attribute %s",
inst->config->xlat_name, group_name);
return -1;
}
- dattr = dict_attrbyname(group_name);
- if (!dattr) {
+ da = dict_attrbyname(group_name);
+ if (!da) {
ERROR("rlm_sql (%s): Failed to create "
"attribute %s", inst->config->xlat_name, group_name);
return -1;
inst->config->groupmemb_query[0]) {
DEBUG("rlm_sql (%s): Registering sql_groupcmp for %s",
inst->config->xlat_name, group_name);
- paircompare_register(dattr, dict_attrbyvalue(PW_USER_NAME, 0),
+ paircompare_register(da, dict_attrbyvalue(PW_USER_NAME, 0),
false, sql_groupcmp, inst);
}
}
/*
* If the configuration parameters can't be parsed, then fail.
*/
- if ((parse_sub_section(conf, inst,
- &inst->config->accounting,
- RLM_COMPONENT_ACCT) < 0) ||
- (parse_sub_section(conf, inst,
- &inst->config->postauth,
- RLM_COMPONENT_POST_AUTH) < 0)) {
+ if ((parse_sub_section(conf, inst, &inst->config->accounting, RLM_COMPONENT_ACCT) < 0) ||
+ (parse_sub_section(conf, inst, &inst->config->postauth, RLM_COMPONENT_POST_AUTH) < 0)) {
cf_log_err_cs(conf, "Invalid configuration");
return -1;
}
inst->config->sql_driver_name,
dlerror());
ERROR("Make sure it (and all its dependent libraries!)"
- "are in the search path of your system's ld.");
+ "are in the search path of your system's ld");
return -1;
}
}
}
+ inst->lf = fr_logfile_init(inst);
+ if (!inst->lf) {
+ cf_log_err_cs(conf, "Failed creating log file context");
+ return -1;
+ }
+
INFO("rlm_sql (%s): Driver %s (module %s) loaded and linked",
inst->config->xlat_name, inst->config->sql_driver_name,
inst->module->name);
if (inst->config->do_clients) {
if (generate_sql_clients(inst) == -1){
- ERROR("Failed to load clients from SQL.");
+ ERROR("Failed to load clients from SQL");
return -1;
}
}
}
-static rlm_rcode_t mod_authorize(void *instance, REQUEST * request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST * request)
{
rlm_rcode_t rcode = RLM_MODULE_NOOP;
char *expanded = NULL;
+ rad_assert(request->packet != NULL);
+ rad_assert(request->reply != NULL);
+
/*
* Set, escape, and check the user attr here
*/
goto error;
}
- if (rows == 0) {
- goto skipreply;
- }
+ if (rows == 0) goto skipreply; /* Don't need to free VPs we don't have */
/*
* Only do this if *some* check pairs were returned
RDEBUG2("User found in radcheck table");
user_found = true;
if (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) != 0) {
+ pairfree(&check_tmp);
+ check_tmp = NULL;
goto skipreply;
}
RDEBUG2("Check items matched");
- radius_xlat_move(request, &request->config_items, &check_tmp);
+ radius_pairmove(request, &request->config_items, check_tmp, true);
rcode = RLM_MODULE_OK;
+ check_tmp = NULL;
}
if (inst->config->authorize_reply_query && (inst->config->authorize_reply_query[0] != '\0')) {
* Now get the reply pairs since the paircompare matched
*/
if (radius_axlat(&expanded, request, inst->config->authorize_reply_query,
- sql_escape_func, inst) < 0) {
+ sql_escape_func, inst) < 0) {
REDEBUG("Error generating query");
rcode = RLM_MODULE_FAIL;
goto error;
goto error;
}
- if (rows == 0) {
- goto skipreply;
- }
+ if (rows == 0) goto skipreply;
if (!inst->config->read_groups) {
dofallthrough = fallthrough(reply_tmp);
RDEBUG2("User found in radreply table");
user_found = true;
- radius_xlat_move(request, &request->reply->vps, &reply_tmp);
+ radius_pairmove(request, &request->reply->vps, reply_tmp, true);
rcode = RLM_MODULE_OK;
+ reply_tmp = NULL;
}
- skipreply:
-
- /*
- * Clear out the pairlists
- */
- pairfree(&check_tmp);
- pairfree(&reply_tmp);
-
+skipreply:
/*
* dofallthrough is set to 1 by default so that if the user information
* is not found, we will still process groups. If the user information,
rlm_rcode_t ret;
RDEBUG3("... falling-through to group processing");
- ret = rlm_sql_process_groups(inst, request, handle, &dofallthrough);
+ ret = rlm_sql_process_groups(inst, request, &handle, &dofallthrough);
switch (ret) {
/*
* Nothing bad happened, continue...
rlm_rcode_t ret;
/*
- * Check for a default_profile or for a User-Profile.
+ * Check for a default_profile or for a User-Profile.
*/
RDEBUG3("... falling-through to profile processing");
user_profile = pairfind(request->config_items, PW_USER_PROFILE, 0, TAG_ANY);
goto error;
}
- ret = rlm_sql_process_groups(inst, request, handle, &dofallthrough);
+ ret = rlm_sql_process_groups(inst, request, &handle, &dofallthrough);
switch (ret) {
/*
* Nothing bad happened, continue...
* At this point the key (user) hasn't be found in the check table, the reply table
* or the group mapping table, and there was no matching profile.
*/
- release:
+release:
if (!user_found) {
rcode = RLM_MODULE_NOTFOUND;
}
- error:
sql_release_socket(inst, handle);
+ return rcode;
+
+error:
pairfree(&check_tmp);
pairfree(&reply_tmp);
+ sql_release_socket(inst, handle);
+
return rcode;
}
*/
sql_ret = rlm_sql_query(&handle, inst, expanded);
TALLOC_FREE(expanded);
-
if (sql_ret == RLM_SQL_RECONNECT) {
rcode = RLM_MODULE_FAIL;
-
goto finish;
}
rad_assert(handle);
/*
* Assume all other errors are incidental, and just meant our
* operation failed and its not a client or SQL syntax error.
+ *
+ * @fixme We should actually be able to distinguish between key
+ * constraint violations (which we expect) and other errors.
*/
- if (sql_ret == 0) {
+ if (sql_ret == RLM_SQL_OK) {
numaffected = (inst->module->sql_affected_rows)(handle, inst->config);
if (numaffected > 0) {
- break;
+ break; /* A query succeeded, were done! */
}
RDEBUG("No records updated");
(inst->module->sql_finish_query)(handle, inst->config);
- finish:
+finish:
talloc_free(expanded);
sql_release_socket(inst, handle);
/*
* Accounting: Insert or update session data in our sql table
*/
-static rlm_rcode_t mod_accounting(void *instance, REQUEST * request) {
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST * request) {
rlm_sql_t *inst = instance;
if (inst->config->accounting) {
* logins by querying the terminal server (using eg. SNMP).
*/
-static rlm_rcode_t mod_checksimul(void *instance, REQUEST * request) {
+static rlm_rcode_t CC_HINT(nonnull) mod_checksimul(void *instance, REQUEST * request) {
rlm_rcode_t rcode = RLM_MODULE_OK;
rlm_sql_handle_t *handle = NULL;
rlm_sql_t *inst = instance;
VALUE_PAIR *vp;
int ret;
uint32_t nas_addr = 0;
- int nas_port = 0;
+ uint32_t nas_port = 0;
char *expanded = NULL;
return RLM_MODULE_FAIL;
}
- if (rlm_sql_select_query(&handle, inst, expanded)) {
+ if (rlm_sql_select_query(&handle, inst, expanded) != RLM_SQL_OK) {
rcode = RLM_MODULE_FAIL;
goto finish;
}
(inst->module->sql_finish_select_query)(handle, inst->config);
TALLOC_FREE(expanded);
- if(request->simul_count < request->simul_max) {
+ if (request->simul_count < request->simul_max) {
rcode = RLM_MODULE_OK;
goto finish;
}
goto finish;
}
- if(rlm_sql_select_query(&handle, inst, expanded)) {
+ if (rlm_sql_select_query(&handle, inst, expanded) != RLM_SQL_OK) {
goto finish;
}
}
if (!row[2]){
- RDEBUG("Cannot zap stale entry. No username present in entry.", inst->config->xlat_name);
+ RDEBUG("Cannot zap stale entry. No username present in entry");
rcode = RLM_MODULE_FAIL;
goto finish;
}
if (!row[1]){
- RDEBUG("Cannot zap stale entry. No session id in entry.", inst->config->xlat_name);
+ RDEBUG("Cannot zap stale entry. No session id in entry");
rcode = RLM_MODULE_FAIL;
goto finish;
/*
* Postauth: Write a record of the authentication attempt
*/
-static rlm_rcode_t mod_post_auth(void *instance, REQUEST * request) {
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST * request) {
rlm_sql_t *inst = instance;
if (inst->config->postauth) {
#include <freeradius-devel/connection.h>
#include <freeradius-devel/modpriv.h>
-#define MAX_QUERY_LEN 4096
-
#define PW_ITEM_CHECK 0
#define PW_ITEM_REPLY 1
/* SQL Errors */
typedef enum {
- RLM_SQL_QUERY_ERROR = -3,
- RLM_SQL_ERROR = -2,
- RLM_SQL_OK = 0,
- RLM_SQL_RECONNECT = 1
+ RLM_SQL_QUERY_ERROR = -3, //!< Query syntax error
+ RLM_SQL_ERROR = -2, //!< General connection/server error
+ RLM_SQL_OK = 0, //!< Success
+ RLM_SQL_RECONNECT = 1, //!< Stale connection, should reconnect
+ RLM_SQL_DUPLICATE = 2 //!< Key constraint violation
} sql_rcode_t;
typedef char **rlm_sql_row_t;
char const *default_profile;
char const *client_query;
+
+ char const *open_query;
char const *authorize_check_query;
char const *authorize_reply_query;
char const *authorize_group_check_query;
char const *simul_verify_query;
char const *groupmemb_query;
- bool const do_clients;
- bool const read_groups;
+ bool do_clients;
+ bool read_groups;
char const *logfile;
- bool const deletestalesessions;
+ bool deletestalesessions;
char const *allowed_chars;
- int const query_timeout;
+ uint32_t query_timeout;
void *driver; //!< Where drivers should write a
//!< pointer to their configurations.
typedef struct sql_inst rlm_sql_t;
typedef struct rlm_sql_handle {
- void *conn;
- rlm_sql_row_t row;
- rlm_sql_t *inst;
+ void *conn; //!< Database specific connection handle.
+ rlm_sql_row_t row; //!< Row data from the last query.
+ rlm_sql_t *inst; //!< The rlm_sql instance this connection belongs to.
} rlm_sql_handle_t;
typedef struct rlm_sql_module_t {
DICT_ATTR const *sql_user; //!< Cached pointer to SQL-User-Name
//!< dictionary attribute.
+ fr_logfile_t *lf;
void *handle;
rlm_sql_module_t *module;
struct sql_grouplist *next;
} rlm_sql_grouplist_t;
-int sql_socket_pool_init(rlm_sql_t *inst);
-void sql_poolfree(rlm_sql_t *inst);
-int sql_close_socket(rlm_sql_t *inst, rlm_sql_handle_t *handle);
+int sql_socket_pool_init(rlm_sql_t *inst);
+void sql_poolfree(rlm_sql_t *inst);
+int sql_close_socket(rlm_sql_t *inst, rlm_sql_handle_t *handle);
rlm_sql_handle_t *sql_get_socket(rlm_sql_t *inst);
-int sql_release_socket(rlm_sql_t *inst, rlm_sql_handle_t *handle);
-int sql_userparse(TALLOC_CTX *ctx, VALUE_PAIR **first_pair, rlm_sql_row_t row);
-int sql_read_realms(rlm_sql_handle_t *handle);
-int sql_getvpdata(rlm_sql_t *inst, rlm_sql_handle_t **handle, TALLOC_CTX *ctx, VALUE_PAIR **pair, char const *query);
-int sql_read_naslist(rlm_sql_handle_t *handle);
-int sql_read_clients(rlm_sql_handle_t *handle);
-int sql_dict_init(rlm_sql_handle_t *handle);
-void rlm_sql_query_log(rlm_sql_t *inst, REQUEST *request,
- sql_acct_section_t *section, char const *query);
-int rlm_sql_select_query(rlm_sql_handle_t **handle, rlm_sql_t *inst, char const *query);
-int rlm_sql_query(rlm_sql_handle_t **handle, rlm_sql_t *inst, char const *query);
-int rlm_sql_fetch_row(rlm_sql_handle_t **handle, rlm_sql_t *inst);
-int sql_set_user(rlm_sql_t *inst, REQUEST *request, char const *username);
+int sql_release_socket(rlm_sql_t *inst, rlm_sql_handle_t *handle);
+int sql_userparse(TALLOC_CTX *ctx, VALUE_PAIR **first_pair, rlm_sql_row_t row);
+int sql_read_realms(rlm_sql_handle_t *handle);
+int sql_getvpdata(rlm_sql_t *inst, rlm_sql_handle_t **handle, TALLOC_CTX *ctx, VALUE_PAIR **pair, char const *query);
+int sql_read_naslist(rlm_sql_handle_t *handle);
+int sql_read_clients(rlm_sql_handle_t *handle);
+int sql_dict_init(rlm_sql_handle_t *handle);
+void CC_HINT(nonnull (1, 2, 4)) rlm_sql_query_log(rlm_sql_t *inst, REQUEST *request, sql_acct_section_t *section, char const *query);
+sql_rcode_t CC_HINT(nonnull) rlm_sql_select_query(rlm_sql_handle_t **handle, rlm_sql_t *inst, char const *query);
+sql_rcode_t CC_HINT(nonnull) rlm_sql_query(rlm_sql_handle_t **handle, rlm_sql_t *inst, char const *query);
+int rlm_sql_fetch_row(rlm_sql_handle_t **handle, rlm_sql_t *inst);
+int sql_set_user(rlm_sql_t *inst, REQUEST *request, char const *username);
#endif
talloc_set_destructor((void *) handle, sql_conn_destructor);
rcode = (inst->module->sql_socket_init)(handle, inst->config);
- if (rcode == 0) {
- exec_trigger(NULL, inst->cs, "modules.sql.open", false);
+ if (rcode != 0) {
+ fail:
+ exec_trigger(NULL, inst->cs, "modules.sql.fail", true);
- return handle;
+ /*
+ * Destroy any half opened connections.
+ */
+ talloc_free(handle);
+ return NULL;
}
- exec_trigger(NULL, inst->cs, "modules.sql.fail", true);
+ if (inst->config->open_query && *inst->config->open_query) {
+ if (rlm_sql_select_query(&handle, inst, inst->config->open_query)) {
+ goto fail;
+ }
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+ }
- /*
- * Destroy any half opened connections.
- */
- talloc_free(handle);
- return NULL;
+ exec_trigger(NULL, inst->cs, "modules.sql.open", false);
+ return handle;
}
/*
* Verify the 'Attribute' field
*/
if (!row[2] || row[2][0] == '\0') {
- ERROR("rlm_sql: The 'Attribute' field is empty or NULL, skipping the entire row.");
+ ERROR("rlm_sql: The 'Attribute' field is empty or NULL, skipping the entire row");
return -1;
}
*/
if (row[4] != NULL && row[4][0] != '\0') {
ptr = row[4];
- operator = gettoken(&ptr, buf, sizeof(buf));
+ operator = gettoken(&ptr, buf, sizeof(buf), false);
if ((operator < T_OP_ADD) ||
(operator > T_OP_CMP_EQ)) {
ERROR("rlm_sql: Invalid operator \"%s\" for attribute %s", row[4], row[2]);
*/
operator = T_OP_CMP_EQ;
ERROR("rlm_sql: The 'op' field for attribute '%s = %s' is NULL, or non-existent.", row[2], row[3]);
- ERROR("rlm_sql: You MUST FIX THIS if you want the configuration to behave as you expect.");
+ ERROR("rlm_sql: You MUST FIX THIS if you want the configuration to behave as you expect");
}
/*
((row[3][0] == '\'') || (row[3][0] == '`') || (row[3][0] == '"')) &&
(row[3][0] == row[3][strlen(row[3])-1])) {
- token = gettoken(&value, buf, sizeof(buf));
+ token = gettoken(&value, buf, sizeof(buf), false);
switch (token) {
/*
* Take the unquoted string.
return -1;
}
} else {
- if (!pairparsevalue(vp, value)) {
- ERROR("rlm_sql: Error parsing value");
+ if (pairparsevalue(vp, value, 0) < 0) {
+ ERROR("rlm_sql: Error parsing value: %s", fr_strerror());
talloc_free(vp);
return -1;
* that connection.
*/
ret = (inst->module->sql_fetch_row)(*handle, inst->config);
-
if (ret < 0) {
char const *error = (inst->module->sql_error)(*handle, inst->config);
- EDEBUG("rlm_sql (%s): Error fetching row: %s",
+ ERROR("rlm_sql (%s): Error fetching row: %s",
inst->config->xlat_name, error ? error : "<UNKNOWN>");
}
return ret;
}
-/*************************************************************************
- *
- * Function: rlm_sql_query
- *
- * Purpose: call the module's sql_query and implement re-connect
- *
- *************************************************************************/
-int rlm_sql_query(rlm_sql_handle_t **handle, rlm_sql_t *inst, char const *query)
+static void rlm_sql_query_error(rlm_sql_handle_t *handle, rlm_sql_t *inst)
{
- int ret = -1;
+ char const *p, *q;
+
+ p = (inst->module->sql_error)(handle, inst->config);
+ if (!p) {
+ ERROR("rlm_sql (%s): Unknown query error", inst->config->xlat_name);
+ return;
+ }
/*
- * If there's no query, return an error.
+ * Some drivers are nice and provide us with a ^ pointer to
+ * the place in the query string where the error occurred.
+ *
+ * For this to be useful we need to split log messages on
+ * \n and output each of the lines individually.
*/
- if (!query || !*query) {
- return -1;
+ while ((q = strchr(p, '\n'))) {
+ ERROR("rlm_sql (%s): %.*s", inst->config->xlat_name, (int) (q - p), p);
+ p = q + 1;
}
- if (!*handle || !(*handle)->conn) {
- goto sql_down;
+ if (*p != '\0') {
+ ERROR("rlm_sql (%s): %s", inst->config->xlat_name, p);
}
+}
+
+static void rlm_sql_query_debug(rlm_sql_handle_t *handle, rlm_sql_t *inst)
+{
+ char const *p, *q;
+
+ p = (inst->module->sql_error)(handle, inst->config);
+ if (!p) {
+ return;
+ }
+
+ /*
+ * Some drivers are nice and provide us with a ^ pointer to
+ * the place in the query string where the error occurred.
+ *
+ * For this to be useful we need to split log messages on
+ * \n and output each of the lines individually.
+ */
+ while ((q = strchr(p, '\n'))) {
+ DEBUG2("rlm_sql (%s): %.*s", inst->config->xlat_name, (int) (q - p), p);
+ p = q + 1;
+ }
+
+ if (*p != '\0') {
+ DEBUG2("rlm_sql (%s): %s", inst->config->xlat_name, p);
+ }
+}
+
+/** Call the driver's sql_query method, reconnecting if necessary.
+ *
+ * @param handle to query the database with. *handle should not be NULL, as this indicates
+ * previous reconnection attempt has failed.
+ * @param inst rlm_sql instance data.
+ * @param query to execute. Should not be zero length.
+ * @return RLM_SQL_OK on success, RLM_SQL_RECONNECT if a new handle is required (also sets *handle = NULL),
+ * RLM_SQL_QUERY_ERROR/RLM_SQL_ERROR on invalid query or connection error, RLM_SQL_DUPLICATE on constraints
+ * violation.
+ */
+sql_rcode_t rlm_sql_query(rlm_sql_handle_t **handle, rlm_sql_t *inst, char const *query)
+{
+ int ret = RLM_SQL_ERROR;
+ int i;
- while (1) {
- DEBUG("rlm_sql (%s): Executing query: '%s'",
- inst->config->xlat_name, query);
+ /* There's no query to run, return an error */
+ if (query[0] == '\0') return RLM_SQL_QUERY_ERROR;
+
+ /* There's no handle, we need a new one */
+ if (!*handle) return RLM_SQL_RECONNECT;
+
+ /* For sanity, for when no connections are viable, and we can't make a new one */
+ for (i = fr_connection_get_num(inst->pool); i >= 0; i--) {
+ DEBUG("rlm_sql (%s): Executing query: '%s'", inst->config->xlat_name, query);
ret = (inst->module->sql_query)(*handle, inst->config, query);
+ switch (ret) {
+ case RLM_SQL_OK:
+ break;
+
/*
- * Run through all available sockets until we exhaust all existing
- * sockets in the pool and fail to establish a *new* connection.
+ * Run through all available sockets until we exhaust all existing
+ * sockets in the pool and fail to establish a *new* connection.
*/
- if (ret == RLM_SQL_RECONNECT) {
- sql_down:
+ case RLM_SQL_RECONNECT:
*handle = fr_connection_reconnect(inst->pool, *handle);
+ /* Reconnection failed */
if (!*handle) return RLM_SQL_RECONNECT;
-
+ /* Reconnection succeeded, try again with the new handle */
continue;
- }
- if (ret < 0) {
- char const *error = (inst->module->sql_error)(*handle, inst->config);
- ERROR("rlm_sql (%s): Database query error: %s",
- inst->config->xlat_name, error ? error : "<UNKNOWN>");
+ case RLM_SQL_QUERY_ERROR:
+ case RLM_SQL_ERROR:
+ rlm_sql_query_error(*handle, inst);
+ break;
+
+ case RLM_SQL_DUPLICATE:
+ rlm_sql_query_debug(*handle, inst);
+ break;
+
}
return ret;
}
+
+ ERROR("rlm_sql (%s): Hit reconnection limit", inst->config->xlat_name);
+
+ return RLM_SQL_ERROR;
}
-/*************************************************************************
+/** Call the driver's sql_select_query method, reconnecting if necessary.
*
- * Function: rlm_sql_select_query
- *
- * Purpose: call the module's sql_select_query and implement re-connect
- *
- *************************************************************************/
-int rlm_sql_select_query(rlm_sql_handle_t **handle, rlm_sql_t *inst, char const *query)
+ * @param handle to query the database with. *handle should not be NULL, as this indicates
+ * previous reconnection attempt has failed.
+ * @param inst rlm_sql instance data.
+ * @param query to execute. Should not be zero length.
+ * @return RLM_SQL_OK on success, RLM_SQL_RECONNECT if a new handle is required (also sets *handle = NULL),
+ * RLM_SQL_QUERY_ERROR/RLM_SQL_ERROR on invalid query or connection error.
+ */
+sql_rcode_t rlm_sql_select_query(rlm_sql_handle_t **handle, rlm_sql_t *inst, char const *query)
{
- int ret = -1;
+ int ret = RLM_SQL_ERROR;
+ int i;
- /*
- * If there's no query, return an error.
- */
- if (!query || !*query) {
- return -1;
- }
+ /* There's no query to run, return an error */
+ if (query[0] == '\0') return RLM_SQL_QUERY_ERROR;
- if (!*handle || !(*handle)->conn) {
- goto sql_down;
- }
+ /* There's no handle, we need a new one */
+ if (!*handle) return RLM_SQL_RECONNECT;
- while (1) {
- DEBUG("rlm_sql (%s): Executing query: '%s'",
- inst->config->xlat_name, query);
+ /* For sanity, for when no connections are viable, and we can't make a new one */
+ for (i = fr_connection_get_num(inst->pool); i >= 0; i--) {
+ DEBUG("rlm_sql (%s): Executing query: '%s'", inst->config->xlat_name, query);
ret = (inst->module->sql_select_query)(*handle, inst->config, query);
+ switch (ret) {
+ case RLM_SQL_OK:
+ break;
+
/*
- * Run through all available sockets until we exhaust all existing
- * sockets in the pool and fail to establish a *new* connection.
+ * Run through all available sockets until we exhaust all existing
+ * sockets in the pool and fail to establish a *new* connection.
*/
- if (ret == RLM_SQL_RECONNECT) {
- sql_down:
+ case RLM_SQL_RECONNECT:
*handle = fr_connection_reconnect(inst->pool, *handle);
+ /* Reconnection failed */
if (!*handle) return RLM_SQL_RECONNECT;
-
+ /* Reconnection succeeded, try again with the new handle */
continue;
- }
- if (ret < 0) {
- char const *error = (inst->module->sql_error)(*handle, inst->config);
- ERROR("rlm_sql (%s): Database query error '%s'",
- inst->config->xlat_name, error ? error : "<UNKNOWN>");
+ case RLM_SQL_QUERY_ERROR:
+ case RLM_SQL_ERROR:
+ default:
+ rlm_sql_query_error(*handle, inst);
+ break;
}
return ret;
}
+
+ ERROR("rlm_sql (%s): Hit reconnection limit", inst->config->xlat_name);
+
+ return RLM_SQL_ERROR;
}
if (!row)
break;
if (sql_userparse(ctx, pair, row) != 0) {
- ERROR("rlm_sql (%s): Error getting data from database", inst->config->xlat_name);
+ ERROR("rlm_sql (%s): Error parsing user data from database result", inst->config->xlat_name);
(inst->module->sql_finish_select_query)(*handle, inst->config);
int fd;
char const *filename = NULL;
char *expanded = NULL;
+ size_t len;
+ bool failed = false; /* Write the log message outside of the critical region */
if (section) {
filename = section->logfile;
return;
}
- fd = open(filename, O_WRONLY | O_APPEND | O_CREAT, 0666);
+ fd = fr_logfile_open(inst->lf, filename, 0640);
if (fd < 0) {
ERROR("rlm_sql (%s): Couldn't open logfile '%s': %s", inst->config->xlat_name,
- expanded, strerror(errno));
+ expanded, fr_syserror(errno));
talloc_free(expanded);
return;
}
- if ((rad_lockfd(fd, MAX_QUERY_LEN) < 0) || (write(fd, query, strlen(query)) < 0) || (write(fd, ";\n", 2) < 0)) {
+ len = strlen(query);
+ if ((write(fd, query, len) < 0) || (write(fd, ";\n", 2) < 0)) {
+ failed = true;
+ }
+
+ if (failed) {
ERROR("rlm_sql (%s): Failed writing to logfile '%s': %s", inst->config->xlat_name, expanded,
- strerror(errno));
+ fr_syserror(errno));
}
talloc_free(expanded);
- close(fd); /* and release the lock */
+ fr_logfile_close(inst->lf, fd);
}
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
CPP C preprocessor
Use these variables to override the choices made by `configure' or to help
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
* be used as the instance handle.
*/
typedef struct rlm_sqlcounter_t {
- char *counter_name; //!< Daily-Session-Time.
- char *check_name; //!< Max-Daily-Session.
- char *reply_name; //!< Session-Timeout.
- char *key_name; //!< User-Name.
- char *sqlmod_inst; //!< Instance of SQL module to use,
+ char const *counter_name; //!< Daily-Session-Time.
+ char const *limit_name; //!< Max-Daily-Session.
+ char const *reply_name; //!< Session-Timeout.
+ char const *key_name; //!< User-Name.
+ char const *sqlmod_inst; //!< Instance of SQL module to use,
//!< usually just 'sql'.
- char *query; //!< SQL query to retrieve current
+ char const *query; //!< SQL query to retrieve current
//!< session time.
- char *reset; //!< Daily, weekly, monthly,
+ char const *reset; //!< Daily, weekly, monthly,
//!< never or user defined.
time_t reset_time;
time_t last_reset;
* buffer over-flows.
*/
static const CONF_PARSER module_config[] = {
- { "sql-module-instance", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_sqlcounter_t,sqlmod_inst), NULL, NULL },
- { "sql_module_instance", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
- offsetof(rlm_sqlcounter_t,sqlmod_inst), NULL, NULL },
-
- { "key", PW_TYPE_STRING_PTR | PW_TYPE_ATTRIBUTE,
- offsetof(rlm_sqlcounter_t,key_name), NULL, NULL },
- { "query", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
- offsetof(rlm_sqlcounter_t,query), NULL, NULL },
- { "reset", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
- offsetof(rlm_sqlcounter_t,reset), NULL, NULL },
-
- { "counter-name", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_sqlcounter_t,counter_name), NULL, NULL },
- { "counter_name", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
- offsetof(rlm_sqlcounter_t,counter_name), NULL, NULL },
-
- { "check-name", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_sqlcounter_t,check_name), NULL, NULL },
- { "check_name", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
- offsetof(rlm_sqlcounter_t,check_name), NULL, NULL },
-
- { "reply-name", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_sqlcounter_t,reply_name), NULL, NULL },
- { "reply_name", PW_TYPE_STRING_PTR | PW_TYPE_ATTRIBUTE,
- offsetof(rlm_sqlcounter_t,reply_name), NULL, "Session-Timeout" },
+ { "sql-module-instance", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlcounter_t, sqlmod_inst), NULL },
+ { "sql_module_instance", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlcounter_t, sqlmod_inst), NULL },
+
+ { "key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_ATTRIBUTE, rlm_sqlcounter_t, key_name), NULL },
+ { "query", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlcounter_t, query), NULL },
+ { "reset", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlcounter_t, reset), NULL },
+
+ { "counter-name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlcounter_t, counter_name), NULL },
+ { "counter_name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlcounter_t, counter_name), NULL },
+
+ { "check-name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlcounter_t, limit_name), NULL },
+ { "check_name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlcounter_t, limit_name), NULL },
+
+ { "reply-name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlcounter_t, reply_name), NULL },
+ { "reply_name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_ATTRIBUTE, rlm_sqlcounter_t, reply_name), "Session-Timeout" },
{ NULL, -1, 0, NULL, NULL }
};
static size_t sqlcounter_expand(char *out, int outlen, char const *fmt, rlm_sqlcounter_t *inst)
{
- int c,freespace;
+ int c, freespace;
char const *p;
char *q;
char tmpdt[40]; /* For temporary storing of dates */
q = out;
for (p = fmt; *p ; p++) {
- /* Calculate freespace in output */
- freespace = outlen - (q - out);
- if (freespace <= 1)
+ /* Calculate freespace in output */
+ freespace = outlen - (q - out);
+ if (freespace <= 1) {
return -1;
+ }
c = *p;
- if ((c != '%') && (c != '\\')) {
+ if (c != '%') {
*q++ = *p;
continue;
}
if (*++p == '\0') break;
- if (c == '\\') switch(*p) {
- case '\\':
- *q++ = *p;
- break;
- case 't':
- *q++ = '\t';
- break;
- case 'n':
- *q++ = '\n';
- break;
- default:
- *q++ = c;
- *q++ = *p;
- break;
-
- } else if (c == '%') switch(*p) {
-
- case '%':
- *q++ = *p;
- break;
+ if (c == '%') switch(*p) {
case 'b': /* last_reset */
snprintf(tmpdt, sizeof(tmpdt), "%" PRId64, (int64_t) inst->last_reset);
strlcpy(q, tmpdt, freespace);
q += strlen(q);
break;
case 'k': /* Key Name */
- WDEBUG2("Please replace '%%k' with '${key}'");
+ WARN("Please replace '%%k' with '${key}'");
strlcpy(q, inst->key_name, freespace);
q += strlen(q);
break;
}
*q = '\0';
- DEBUG2("sqlcounter_expand: '%s'", out);
+ DEBUG2("sqlcounter_expand: '%s'", out);
return strlen(out);
}
rlm_sqlcounter_t *inst = instance;
uint64_t counter;
- char *p;
- char query[MAX_QUERY_LEN];
+ char query[MAX_QUERY_LEN], subst[MAX_QUERY_LEN];
char *expanded = NULL;
-
size_t len;
- len = snprintf(query, sizeof(query), "%%{%s:%s}", inst->sqlmod_inst, inst->query);
- if (len >= sizeof(query) - 1) {
+ /* First, expand %k, %b and %e in query */
+ if (sqlcounter_expand(subst, sizeof(subst), inst->query, inst) <= 0) {
REDEBUG("Insufficient query buffer space");
return RLM_MODULE_FAIL;
}
- p = query + len;
-
- /* first, expand %k, %b and %e in query */
- len = sqlcounter_expand(p, p - query, inst->query, inst);
- if (len <= 0) {
- REDEBUG("Insufficient query buffer space");
-
- return RLM_MODULE_FAIL;
- }
-
- p += len;
-
- if ((p - query) < 2) {
+ /* Then combine that with the name of the module were using to do the query */
+ len = snprintf(query, sizeof(query), "%%{%s:%s}", inst->sqlmod_inst, subst);
+ if (len >= sizeof(query) - 1) {
REDEBUG("Insufficient query buffer space");
return RLM_MODULE_FAIL;
}
- p[0] = '}';
- p[1] = '\0';
-
/* Finally, xlat resulting SQL query */
if (radius_axlat(&expanded, request, query, NULL, NULL) < 0) {
return RLM_MODULE_FAIL;
}
- counter = strtoull(expanded, NULL, 10);
+ if (sscanf(expanded, "%" PRIu64, &counter) != 1) {
+ RDEBUG2("No integer found in string \"%s\"", expanded);
+ }
talloc_free(expanded);
if (counter < check->vp_integer64) {
*/
rad_assert(inst->counter_name && *inst->counter_name);
memset(&flags, 0, sizeof(flags));
- dict_addattr(inst->counter_name, -1, 0, PW_TYPE_INTEGER, flags);
+ dict_addattr(inst->counter_name, -1, 0, PW_TYPE_INTEGER64, flags);
da = dict_attrbyname(inst->counter_name);
if (!da) {
cf_log_err_cs(conf, "Failed to create counter attribute %s", inst->counter_name);
inst->dict_attr = da;
/*
- * Create a new attribute for the check item.
+ * Create a new attribute for the check item.
*/
- rad_assert(inst->check_name && *inst->check_name);
- dict_addattr(inst->check_name, 0, PW_TYPE_INTEGER, -1, flags);
- da = dict_attrbyname(inst->check_name);
+ rad_assert(inst->limit_name && *inst->limit_name);
+ dict_addattr(inst->limit_name, -1, 0, PW_TYPE_INTEGER64, flags);
+ da = dict_attrbyname(inst->limit_name);
if (!da) {
- cf_log_err_cs(conf, "Failed to create check attribute %s", inst->check_name);
+ cf_log_err_cs(conf, "Failed to create check attribute %s", inst->limit_name);
return -1;
}
}
/*
- * Register the counter comparison operation.
+ * Register the counter comparison operation.
*/
paircompare_register(inst->dict_attr, NULL, true, sqlcounter_cmp, inst);
* from the database. The authentication code only needs to check
* the password, the rest is done here.
*/
-static rlm_rcode_t mod_authorize(UNUSED void *instance, UNUSED REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
{
rlm_sqlcounter_t *inst = instance;
int rcode = RLM_MODULE_NOOP;
uint64_t counter, res;
DICT_ATTR const *da;
- VALUE_PAIR *key_vp, *check_vp;
+ VALUE_PAIR *key_vp, *limit;
VALUE_PAIR *reply_item;
char msg[128];
- char *p;
- char query[MAX_QUERY_LEN];
+ char query[MAX_QUERY_LEN], subst[MAX_QUERY_LEN];
char *expanded = NULL;
size_t len;
* Look for the key. User-Name is special. It means
* The REAL username, after stripping.
*/
- RDEBUG2("Entering module authorize code");
- key_vp = ((inst->key_attr->vendor == 0) && (inst->key_attr->attr == PW_USER_NAME)) ?
- request->username :
- pairfind(request->packet->vps, inst->key_attr->attr, inst->key_attr->vendor, TAG_ANY);
+ if ((inst->key_attr->vendor == 0) && (inst->key_attr->attr == PW_USER_NAME)) {
+ key_vp = request->username;
+ } else {
+ key_vp = pairfind(request->packet->vps, inst->key_attr->attr, inst->key_attr->vendor, TAG_ANY);
+ }
if (!key_vp) {
- RDEBUG2("Could not find Key value pair");
+ RWDEBUG2("Couldn't find key attribute 'request:%s'", inst->key_attr->name);
return rcode;
}
/*
* Look for the check item
*/
- if ((da = dict_attrbyname(inst->check_name)) == NULL) {
+ if ((da = dict_attrbyname(inst->limit_name)) == NULL) {
return rcode;
}
- /* DEBUG2("rlm_sqlcounter: Found Check item attribute %d", da->attr); */
- if ((check_vp = pairfind(request->config_items, da->attr, da->vendor, TAG_ANY)) == NULL) {
- RDEBUG2("Could not find Check item value pair");
- return rcode;
- }
-
- len = snprintf(query, sizeof(query), "%%{%s:%s}", inst->sqlmod_inst, inst->query);
- if (len >= sizeof(query) - 1) {
- REDEBUG("Insufficient query buffer space");
- return RLM_MODULE_FAIL;
+ limit = pairfind(request->config_items, da->attr, da->vendor, TAG_ANY);
+ if (limit == NULL) {
+ RWDEBUG2("Couldn't find control attribute 'control:%s'", inst->limit_name);
+ return rcode;
}
- p = query + len;
-
- /* first, expand %k, %b and %e in query */
- len = sqlcounter_expand(p, p - query, inst->query, inst);
- if (len <= 0) {
+ /* First, expand %k, %b and %e in query */
+ if (sqlcounter_expand(subst, sizeof(subst), inst->query, inst) <= 0) {
REDEBUG("Insufficient query buffer space");
return RLM_MODULE_FAIL;
}
- p += len;
-
- if ((p - query) < 2) {
+ /* Then combine that with the name of the module were using to do the query */
+ len = snprintf(query, sizeof(query), "%%{%s:%s}", inst->sqlmod_inst, subst);
+ if (len >= (sizeof(query) - 1)) {
REDEBUG("Insufficient query buffer space");
return RLM_MODULE_FAIL;
}
- p[0] = '}';
- p[1] = '\0';
-
/* Finally, xlat resulting SQL query */
if (radius_axlat(&expanded, request, query, NULL, NULL) < 0) {
return RLM_MODULE_FAIL;
}
+ talloc_free(expanded);
if (sscanf(expanded, "%" PRIu64, &counter) != 1) {
- RDEBUG2("No integer found in string \"%s\"", expanded);
- return RLM_MODULE_NOOP;
+ RDEBUG2("No integer found in result string \"%s\". May be first session, setting counter to 0",
+ expanded);
+ counter = 0;
}
- talloc_free(expanded);
-
/*
* Check if check item > counter
*/
- if (check_vp->vp_integer64 <= counter) {
- RDEBUG2("(Check item - counter) is less than zero");
-
- /*
- * User is denied access, send back a reply message
- */
+ if (limit->vp_integer64 <= counter) {
+ /* User is denied access, send back a reply message */
snprintf(msg, sizeof(msg), "Your maximum %s usage time has been reached", inst->reset);
pairmake_reply("Reply-Message", msg, T_OP_EQ);
- REDEBUG("Maximum %s usage time reached", inst->reset);
- rcode = RLM_MODULE_REJECT;
-
- RDEBUG2("Rejected user %s, check_item=%" PRIu64 ", counter=%" PRIu64,
- key_vp->vp_strvalue, check_vp->vp_integer64, counter);
+ REDEBUG2("Maximum %s usage time reached", inst->reset);
+ REDEBUG2("Rejecting user, control:%s value (%" PRIu64 ") is less than counter value (%" PRIu64 ")",
+ inst->limit_name, limit->vp_integer64, counter);
return RLM_MODULE_REJECT;
-
}
- res = check_vp->vp_integer64 - counter;
- RDEBUG2("Check item is greater than query result");
+ res = limit->vp_integer64 - counter;
+ RDEBUG2("Allowing user, control:%s value (%" PRIu64 ") is greater than counter value (%" PRIu64 ")",
+ inst->limit_name, limit->vp_integer64, counter);
/*
* We are assuming that simultaneous-use=1. But
* even if that does not happen then our user
*/
if (((inst->reply_attr->vendor == 0) && (inst->reply_attr->attr == PW_SESSION_TIMEOUT)) &&
inst->reset_time && ((int) res >= (inst->reset_time - request->timestamp))) {
- res = inst->reset_time - request->timestamp;
- res += check_vp->vp_integer;
+ res = (inst->reset_time - request->timestamp);
+ res += limit->vp_integer;
}
/*
- * Limit the reply attribute to the minimum of
- * the existing value, or this new one.
+ * Limit the reply attribute to the minimum of the existing value, or this new one.
*/
reply_item = pairfind(request->reply->vps, inst->reply_attr->attr, inst->reply_attr->vendor, TAG_ANY);
if (reply_item) {
- if (reply_item->vp_integer64 > res) {
- reply_item->vp_integer64 = res;
+ if (reply_item->vp_integer64 <= res) {
+ RDEBUG2("Leaving existing reply:%s value of %" PRIu64, inst->reply_attr->name,
+ reply_item->vp_integer64);
+
+ return RLM_MODULE_OK;
}
} else {
- reply_item = radius_paircreate(request, &request->reply->vps, inst->reply_attr->attr,
+ reply_item = radius_paircreate(request->reply, &request->reply->vps, inst->reply_attr->attr,
inst->reply_attr->vendor);
- reply_item->vp_integer64 = res;
}
+ reply_item->vp_integer64 = res;
- RDEBUG2("Authorized user %s, check_item=%" PRIu64 ", counter=%" PRIu64 ,
- key_vp->vp_strvalue, check_vp->vp_integer64, counter);
- RDEBUG2("Sent Reply-Item for user %s, Type=%s, value=%" PRIu64,
- key_vp->vp_strvalue, inst->reply_name, reply_item->vp_integer64);
+ RDEBUG2("Setting reply:%s value to %" PRIu64, inst->reply_name, reply_item->vp_integer64);
return RLM_MODULE_OK;
}
*/
module_t rlm_sqlcounter = {
RLM_MODULE_INIT,
- "SQL Counter",
+ "rlm_sqlcounter",
RLM_TYPE_THREAD_SAFE, /* type */
sizeof(rlm_sqlcounter_t),
module_config,
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
CPP C preprocessor
Use these variables to override the choices made by `configure' or to help
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
--header=FILE[:TEMPLATE]
- instantiate the configuration header FILE
+ instantiate the configuration header FILE
Configuration files:
$config_files
#define RLM_NETVIM_MAX_ROWS 1000000
#define RLM_NETVIM_TMP_PREFIX "auth-tmp-"
-static char const rcsid[] = "$Id$";
+#define MAX_QUERY_LEN 4096
+
+RCSID("$Id$");
typedef struct rlm_sqlhpwippool_t {
- char const *myname; //!< Name of this instance
+ char const *myname; //!< Name of this instance
rlm_sql_t *sqlinst;
rlm_sql_module_t *db;
#ifdef HAVE_PTHREAD_D
- pthread_mutex_t mutex; //!< Used "with" sync_after
+ pthread_mutex_t mutex; //!< Used "with" sync_after
#endif
- int sincesync; //!< req. done so far since last free IP sync.
+ uint32_t sincesync; //!< req. done so far since last free IP sync.
/* from config */
- char *sql_module_instance; //!< rlm_sql instance to use.
- char *db_name; //!< Netvim database.
- bool no_free_fail; //!< Fail if no free IP addresses found.
- int free_after; //!< How many seconds an IP should not be used after freeing.
- int sync_after; //!< How often to sync with radacct.
+ char const *sql_module_instance; //!< rlm_sql instance to use.
+ char const *db_name; //!< Netvim database.
+ bool no_free_fail; //!< Fail if no free IP addresses found.
+ uint32_t free_after; //!< How many seconds an IP should not be used after freeing.
+ uint32_t sync_after; //!< How often to sync with radacct.
} rlm_sqlhpwippool_t;
/* char *name, int type,
* size_t offset, void *data, char *dflt */
static CONF_PARSER module_config[] = {
- { "sql_module_instance", PW_TYPE_STRING_PTR,
- offsetof(rlm_sqlhpwippool_t, sql_module_instance), NULL, "sql" },
- { "db_name", PW_TYPE_STRING_PTR,
- offsetof(rlm_sqlhpwippool_t, db_name), NULL, "netvim" },
- { "no_free_fail", PW_TYPE_BOOLEAN,
- offsetof(rlm_sqlhpwippool_t, no_free_fail), NULL, "yes" },
- { "free_after", PW_TYPE_INTEGER,
- offsetof(rlm_sqlhpwippool_t, free_after), NULL, "300" },
- { "sync_after", PW_TYPE_INTEGER,
- offsetof(rlm_sqlhpwippool_t, sync_after), NULL, "25" },
+ { "sql_module_instance", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlhpwippool_t, sql_module_instance), "sql" },
+ { "db_name", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlhpwippool_t, db_name), "netvim" },
+ { "no_free_fail", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sqlhpwippool_t, no_free_fail), "yes" },
+ { "free_after", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_sqlhpwippool_t, free_after), "300" },
+ { "sync_after", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_sqlhpwippool_t, sync_after), "25" },
{ NULL, -1, 0, NULL, NULL } /* end */
};
+int nvp_log(unsigned int line, rlm_sqlhpwippool_t *data, int lvl, char const *fmt, ...) CC_HINT(format (printf, 4, 5));
+
+DIAG_OFF(format-nonliteral)
/* wrapper around radlog which adds prefix with module and instance name */
-static int nvp_log(unsigned int line, rlm_sqlhpwippool_t *data, int lvl,
- char const *fmt, ...)
+int nvp_log(unsigned int line, rlm_sqlhpwippool_t *data, int lvl, char const *fmt, ...)
{
va_list ap;
int r;
return r;
}
+
/* handy SQL query tool */
-DIAG_OFF(format-nonliteral)
static int nvp_vquery(unsigned int line, rlm_sqlhpwippool_t *data,
rlm_sql_handle_t *sqlsock, char const *fmt, va_list ap)
{
{
if (!nvp_query(__LINE__, data, sqlsock,
"UPDATE `%s`.`ips`, `radacct` "
- "SET "
- "`ips`.`rsv_until` = `radacct`.`acctstoptime` + INTERVAL %u SECOND "
- "WHERE "
- "`radacct`.`acctstoptime` IS NOT NULL AND " /* session is closed */
- "(" /* address is being used */
- "`ips`.`pid` IS NOT NULL AND "
- "(`rsv_until` = 0 OR `rsv_until` > NOW())"
- ") AND "
- "`radacct`.`acctuniqueid` = `ips`.`rsv_by`",
+ "SET "
+ "`ips`.`rsv_until` = `radacct`.`acctstoptime` + INTERVAL %u SECOND "
+ "WHERE "
+ "`radacct`.`acctstoptime` IS NOT NULL AND " /* session is closed */
+ "(" /* address is being used */
+ "`ips`.`pid` IS NOT NULL AND "
+ "(`rsv_until` = 0 OR `rsv_until` > NOW())"
+ ") AND "
+ "`radacct`.`acctuniqueid` = `ips`.`rsv_by`",
data->db_name, data->free_after)) {
return 0;
}
{
if (!nvp_query(__LINE__, data, sqlsock,
"UPDATE `%s`.`ip_pools` "
- "SET `ip_pools`.`free` = "
- "(SELECT COUNT(*) "
- "FROM `%1$s`.`ips` "
- "WHERE "
- "`ips`.`ip` BETWEEN "
- "`ip_pools`.`ip_start` AND `ip_pools`.`ip_stop` AND "
- "("
- "`ips`.`pid` IS NULL OR "
- "(`ips`.`rsv_until` > 0 AND `ips`.`rsv_until` < NOW())"
- "))",
+ "SET `ip_pools`.`free` = "
+ "(SELECT COUNT(*) "
+ "FROM `%1$s`.`ips` "
+ "WHERE "
+ "`ips`.`ip` BETWEEN "
+ "`ip_pools`.`ip_start` AND `ip_pools`.`ip_stop` AND "
+ "("
+ "`ips`.`pid` IS NULL OR "
+ "(`ips`.`rsv_until` > 0 AND `ips`.`rsv_until` < NOW())"
+ "))",
data->db_name)) {
return 0;
}
/* add sessions opened in the meantime */
if (!nvp_query(__LINE__, data, sqlsock,
"UPDATE `%s`.`ips`, `radacct` "
- "SET "
- "`ips`.`pid` = 0, "
- "`ips`.`rsv_by` = `radacct`.`acctuniqueid`, "
- "`ips`.`rsv_since` = `radacct`.`acctstarttime`, "
- "`ips`.`rsv_until` = 0 "
- "WHERE "
- "`radacct`.`acctstoptime` IS NULL AND " /* session is opened */
- "`ips`.`ip` = INET_ATON(`radacct`.`framedipaddress`) AND "
- "("
- "`ips`.`pid` IS NULL OR "
+ "SET "
+ "`ips`.`pid` = 0, "
+ "`ips`.`rsv_by` = `radacct`.`acctuniqueid`, "
+ "`ips`.`rsv_since` = `radacct`.`acctstarttime`, "
+ "`ips`.`rsv_until` = 0 "
+ "WHERE "
+ "`radacct`.`acctstoptime` IS NULL AND " /* session is opened */
+ "`ips`.`ip` = INET_ATON(`radacct`.`framedipaddress`) AND "
+ "("
+ "`ips`.`pid` IS NULL OR "
/* "(`ips`.`rsv_until` > 0 AND `ips.`rsv_until` < NOW()) " */
- "`ips`.`rsv_until` != 0" /* no acct pkt received yet */
- ")",
+ "`ips`.`rsv_until` != 0" /* no acct pkt received yet */
+ ")",
data->db_name)) {
sql_release_socket(data->sqlinst, sqlsock);
return 0;
}
/* assign new IP address, if required */
-static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
{
VALUE_PAIR *vp;
char const *pname; /* name of requested IP pool */
/* find the most specific group which NAS belongs to */
switch (nvp_select(__LINE__, inst, sqlsock,
"SELECT `host_groups`.`gid` "
- "FROM "
- "`%s`.`host_groups`, "
- "`%1$s`.`gid_ip`, "
- "`%1$s`.`ids` "
- "WHERE "
- "`host_groups`.`gid` = `ids`.`id` AND "
- "`ids`.`enabled` = 1 AND "
- "`host_groups`.`gid` = `gid_ip`.`gid` AND "
- "%lu BETWEEN `gid_ip`.`ip_start` AND `gid_ip`.`ip_stop` "
- "ORDER BY (`gid_ip`.`ip_stop` - `gid_ip`.`ip_start`) ASC "
- "LIMIT %lu, 1",
+ "FROM "
+ "`%s`.`host_groups`, "
+ "`%1$s`.`gid_ip`, "
+ "`%1$s`.`ids` "
+ "WHERE "
+ "`host_groups`.`gid` = `ids`.`id` AND "
+ "`ids`.`enabled` = 1 AND "
+ "`host_groups`.`gid` = `gid_ip`.`gid` AND "
+ "%lu BETWEEN `gid_ip`.`ip_start` AND `gid_ip`.`ip_stop` "
+ "ORDER BY (`gid_ip`.`ip_stop` - `gid_ip`.`ip_start`) ASC "
+ "LIMIT %lu, 1",
inst->db_name, nasip, s_gid)) {
case -1:
nvp_log(__LINE__, inst, L_ERR,
"FROM "
"`%s`.`ip_pools`, "
"`%1$s`.`ids`, "
- "`%1$s`.`pool_names` "
+ "`%1$s`.`pool_names` "
"WHERE "
"`ip_pools`.`gid` = %lu AND "
"`ids`.`id` = `ip_pools`.`pid` AND "
case -1:
nvp_log(__LINE__, inst, L_DBG,
"mod_post_auth(): couldn't find "
- "any more matching pools for gid = %u",
+ "any more matching pools for gid = %lu",
gid);
goto end_prio; /* select next gid */
case 0:
/* reserve an IP address */
if (!nvp_query(__LINE__, inst, sqlsock,
"UPDATE `%s`.`ips` "
- "SET "
- "`pid` = %lu, "
- "`rsv_since` = NOW(), "
- "`rsv_by` = '" RLM_NETVIM_TMP_PREFIX "%lu', "
- "`rsv_until` = NOW() + INTERVAL %d SECOND "
- "WHERE "
- "`ip` BETWEEN %lu AND %lu AND "
- "("
- "`pid` IS NULL OR "
- "(`rsv_until` > 0 AND `rsv_until` < NOW())"
- ") "
- "ORDER BY RAND() "
- "LIMIT 1",
+ "SET "
+ "`pid` = %lu, "
+ "`rsv_since` = NOW(), "
+ "`rsv_by` = '" RLM_NETVIM_TMP_PREFIX "%lu', "
+ "`rsv_until` = NOW() + INTERVAL %d SECOND "
+ "WHERE "
+ "`ip` BETWEEN %lu AND %lu AND "
+ "("
+ "`pid` IS NULL OR "
+ "(`rsv_until` > 0 AND `rsv_until` < NOW())"
+ ") "
+ "ORDER BY RAND() "
+ "LIMIT 1",
inst->db_name, pid, connid, inst->free_after, ip_start, ip_stop)) {
sql_release_socket(inst->sqlinst, sqlsock);
return RLM_MODULE_FAIL;
/* update free IPs count */
if (!nvp_query(__LINE__, inst, sqlsock,
"UPDATE `%s`.`ip_pools` "
- "SET "
- "`free` = `free` - 1 "
- "WHERE "
- "`pid` = %lu "
- "LIMIT 1",
+ "SET "
+ "`free` = `free` - 1 "
+ "WHERE "
+ "`pid` = %lu "
+ "LIMIT 1",
inst->db_name, pid)) {
sql_release_socket(inst->sqlinst, sqlsock);
return RLM_MODULE_FAIL;
}
/* add IP address to reply packet */
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
PW_FRAMED_IP_ADDRESS, 0);
vp->vp_ipaddr = ip.s_addr;
return RLM_MODULE_OK;
}
-static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
{
VALUE_PAIR *vp;
rlm_sql_handle_t *sqlsock;
if (!nvp_query(__LINE__, inst, sqlsock,
"UPDATE `%s`.`ips` "
- "SET "
- "`rsv_until` = 0, "
- "`rsv_by` = '%s' "
- "WHERE `ip` = %lu",
+ "SET "
+ "`rsv_until` = 0, "
+ "`rsv_by` = '%s' "
+ "WHERE `ip` = %lu",
inst->db_name, sessid, framedip)) {
sql_release_socket(inst->sqlinst, sqlsock);
return RLM_MODULE_FAIL;
case PW_STATUS_STOP:
if (!nvp_query(__LINE__, inst, sqlsock,
"UPDATE `%s`.`ips`, `%1$s`.`ip_pools` "
- "SET "
- "`ips`.`rsv_until` = NOW() + INTERVAL %u SECOND, "
- "`ip_pools`.`free` = `ip_pools`.`free` + 1 "
- "WHERE "
- "`ips`.`rsv_by` = '%s' AND "
- "`ips`.`ip` BETWEEN `ip_pools`.`ip_start` AND `ip_pools`.`ip_stop`",
+ "SET "
+ "`ips`.`rsv_until` = NOW() + INTERVAL %u SECOND, "
+ "`ip_pools`.`free` = `ip_pools`.`free` + 1 "
+ "WHERE "
+ "`ips`.`rsv_by` = '%s' AND "
+ "`ips`.`ip` BETWEEN `ip_pools`.`ip_start` AND `ip_pools`.`ip_stop`",
inst->db_name, inst->free_after, sessid)) {
sql_release_socket(inst->sqlinst, sqlsock);
return RLM_MODULE_FAIL;
if (!nvp_query(__LINE__, inst, sqlsock,
"UPDATE `%s`.`ips`, `radacct` "
- "SET `ips`.`rsv_until` = NOW() + INTERVAL %u SECOND "
- "WHERE "
- "`radacct`.`nasipaddress` = '%s' AND "
- "`ips`.`rsv_by` = `radacct`.`acctuniqueid`",
+ "SET `ips`.`rsv_until` = NOW() + INTERVAL %u SECOND "
+ "WHERE "
+ "`radacct`.`nasipaddress` = '%s' AND "
+ "`ips`.`rsv_by` = `radacct`.`acctuniqueid`",
inst->db_name, inst->free_after, nasipstr)) {
sql_release_socket(inst->sqlinst, sqlsock);
return RLM_MODULE_FAIL;
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
#include <rlm_sql.h>
+#define MAX_QUERY_LEN 4096
+
/*
* Define a structure for our module configuration.
*/
typedef struct rlm_sqlippool_t {
- char *sql_instance_name;
+ char const *sql_instance_name;
- int lease_duration;
+ uint32_t lease_duration;
rlm_sql_t *sql_inst;
- char *pool_name;
-
- /* We ended up removing the init
- queries so that its up to user
- to create the db structure and put the required
- information in there
- */
- /* Allocation sequence */
- time_t last_clear; /* so we only do it once a second */
- char *allocate_begin; /* SQL query to begin */
- char *allocate_clear; /* SQL query to clear an IP */
- char *allocate_find; /* SQL query to find an unused IP */
- char *allocate_update; /* SQL query to mark an IP as used */
- char *allocate_commit; /* SQL query to commit */
-
- char *pool_check; /* Query to check for the existence of the pool */
-
- /* Start sequence */
- char *start_begin; /* SQL query to begin */
- char *start_update; /* SQL query to update an IP entry */
- char *start_commit; /* SQL query to commit */
-
- /* Alive sequence */
- char *alive_begin; /* SQL query to begin */
- char *alive_update; /* SQL query to update an IP entry */
- char *alive_commit; /* SQL query to commit */
-
- /* Stop sequence */
- char *stop_begin; /* SQL query to begin */
- char *stop_clear; /* SQL query to clear an IP */
- char *stop_commit; /* SQL query to commit */
-
- /* On sequence */
- char *on_begin; /* SQL query to begin */
- char *on_clear; /* SQL query to clear an entire NAS */
- char *on_commit; /* SQL query to commit */
-
- /* Off sequence */
- char *off_begin; /* SQL query to begin */
- char *off_clear; /* SQL query to clear an entire NAS */
- char *off_commit; /* SQL query to commit */
-
- /* Logging Section */
- char *log_exists; /* There was an ip address already assigned */
- char *log_success; /* We successfully allocated ip address from pool */
- char *log_clear; /* We successfully deallocated ip address from pool */
- char *log_failed; /* Failed to allocate ip from the pool */
- char *log_nopool; /* There was no Framed-IP-Address but also no Pool-Name */
-
- /* Reserved to handle 255.255.255.254 Requests */
- char *defaultpool; /* Default Pool-Name if there is none in the check items */
+ char const *pool_name;
+
+ time_t last_clear; //!< So we only do it once a second.
+ char const *allocate_begin; //!< SQL query to begin.
+ char const *allocate_clear; //!< SQL query to clear an IP.
+ char const *allocate_find; //!< SQL query to find an unused IP.
+ char const *allocate_update; //!< SQL query to mark an IP as used.
+ char const *allocate_commit; //!< SQL query to commit.
+
+ char const *pool_check; //!< Query to check for the existence of the pool.
+
+ //!< Start sequence.
+ char const *start_begin; //!< SQL query to begin.
+ char const *start_update; //!< SQL query to update an IP entry.
+ char const *start_commit; //!< SQL query to commit.
+
+ //!< Alive sequence.
+ char const *alive_begin; //!< SQL query to begin.
+ char const *alive_update; //!< SQL query to update an IP entry.
+ char const *alive_commit; //!< SQL query to commit.
+
+ //!< Stop sequence.
+ char const *stop_begin; //!< SQL query to begin.
+ char const *stop_clear; //!< SQL query to clear an IP.
+ char const *stop_commit; //!< SQL query to commit.
+
+ //!< On sequence.
+ char const *on_begin; //!< SQL query to begin.
+ char const *on_clear; //!< SQL query to clear an entire NAS.
+ char const *on_commit; //!< SQL query to commit.
+
+ //!< Off sequence.
+ char const *off_begin; //!< SQL query to begin.
+ char const *off_clear; //!< SQL query to clear an entire NAS.
+ char const *off_commit; //!< SQL query to commit.
+
+ //!< Logging Section.
+ char const *log_exists; //!< There was an ip address already assigned.
+ char const *log_success; //!< We successfully allocated ip address from pool.
+ char const *log_clear; //!< We successfully deallocated ip address from pool.
+ char const *log_failed; //!< Failed to allocate ip from the pool.
+ char const *log_nopool; //!< There was no Framed-IP-Address but also no Pool-Name.
+
+ //!< Reserved to handle 255.255.255.254 Requests.
+ char const *defaultpool; //!< Default Pool-Name if there is none in the check items.
} rlm_sqlippool_t;
static CONF_PARSER message_config[] = {
- { "exists", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, log_exists), NULL, NULL },
- { "success", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, log_success), NULL, NULL },
- { "clear", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, log_clear), NULL, NULL },
- { "failed", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, log_failed), NULL, NULL },
- { "nopool", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, log_nopool), NULL, NULL },
+ { "exists", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, log_exists), NULL },
+ { "success", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, log_success), NULL },
+ { "clear", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, log_clear), NULL },
+ { "failed", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, log_failed), NULL },
+ { "nopool", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, log_nopool), NULL },
{ NULL, -1, 0, NULL, NULL }
};
* buffer over-flows.
*/
static CONF_PARSER module_config[] = {
- {"sql-instance-name",PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_sqlippool_t,sql_instance_name), NULL, NULL},
- {"sql_module_instance",PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
- offsetof(rlm_sqlippool_t,sql_instance_name), NULL, "sql"},
+ { "sql-instance-name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, sql_instance_name), NULL },
+ { "sql_module_instance", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlippool_t, sql_instance_name), "sql" },
- { "lease-duration", PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,lease_duration), NULL, NULL},
- { "lease_duration", PW_TYPE_INTEGER, offsetof(rlm_sqlippool_t,lease_duration), NULL, "86400"},
+ { "lease-duration", FR_CONF_OFFSET(PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, rlm_sqlippool_t, lease_duration), NULL },
+ { "lease_duration", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_sqlippool_t, lease_duration), "86400" },
- { "pool-name", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t, pool_name), NULL, NULL},
- { "pool_name", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, pool_name), NULL, ""},
+ { "pool-name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, pool_name), NULL },
+ { "pool_name", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, pool_name), "" },
- { "default-pool", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t, defaultpool), NULL, NULL },
- { "default_pool", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, defaultpool), NULL, "main_pool" },
+ { "default-pool", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, defaultpool), NULL },
+ { "default_pool", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, defaultpool), "main_pool" },
- { "allocate-begin", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_sqlippool_t,allocate_begin), NULL, NULL},
- { "allocate_begin", PW_TYPE_STRING_PTR,
- offsetof(rlm_sqlippool_t,allocate_begin), NULL, "START TRANSACTION" },
+ { "allocate-begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, allocate_begin), NULL },
+ { "allocate_begin", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, allocate_begin), "START TRANSACTION" },
- { "allocate-clear", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_sqlippool_t,allocate_clear), NULL, NULL},
- { "allocate_clear", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
- offsetof(rlm_sqlippool_t,allocate_clear), NULL, "" },
+ { "allocate-clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, allocate_clear), NULL },
+ { "allocate_clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlippool_t, allocate_clear), "" },
- { "allocate-find", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_sqlippool_t,allocate_find), NULL, NULL},
- { "allocate_find", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
- offsetof(rlm_sqlippool_t,allocate_find), NULL, "" },
+ { "allocate-find", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, allocate_find), NULL },
+ { "allocate_find", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlippool_t, allocate_find), "" },
- { "allocate-update", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_sqlippool_t,allocate_update), NULL, NULL },
- { "allocate_update", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
- offsetof(rlm_sqlippool_t,allocate_update), NULL, "" },
+ { "allocate-update", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, allocate_update), NULL },
+ { "allocate_update", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlippool_t, allocate_update), "" },
- { "allocate-commit", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
- offsetof(rlm_sqlippool_t,allocate_commit), NULL, NULL },
- { "allocate_commit", PW_TYPE_STRING_PTR,
- offsetof(rlm_sqlippool_t,allocate_commit), NULL, "COMMIT" },
+ { "allocate-commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, allocate_commit), NULL },
+ { "allocate_commit", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, allocate_commit), "COMMIT" },
- { "pool-check", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,pool_check), NULL, NULL },
- { "pool_check", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,pool_check), NULL, "" },
+ { "pool-check", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, pool_check), NULL },
+ { "pool_check", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, pool_check), "" },
- { "start-begin", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,start_begin), NULL, NULL },
- { "start_begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,start_begin), NULL, "START TRANSACTION" },
+ { "start-begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, start_begin), NULL },
+ { "start_begin", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, start_begin), "START TRANSACTION" },
- { "start-update", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,start_update), NULL, NULL },
- { "start_update", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED, offsetof(rlm_sqlippool_t,start_update), NULL, "" },
+ { "start-update", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, start_update), NULL },
+ { "start_update", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlippool_t, start_update), "" },
- { "start-commit", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,start_commit), NULL, NULL },
- { "start_commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,start_commit), NULL, "COMMIT" },
+ { "start-commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, start_commit), NULL },
+ { "start_commit", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, start_commit), "COMMIT" },
- { "alive-begin", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,alive_begin), NULL, NULL },
- { "alive_begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,alive_begin), NULL, "START TRANSACTION" },
+ { "alive-begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, alive_begin), NULL },
+ { "alive_begin", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, alive_begin), "START TRANSACTION" },
- { "alive-update", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,alive_update), NULL, NULL },
- { "alive_update", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED, offsetof(rlm_sqlippool_t,alive_update), NULL, "" },
+ { "alive-update", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, alive_update), NULL },
+ { "alive_update", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlippool_t, alive_update), "" },
- { "alive-commit", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,alive_commit), NULL, NULL },
- { "alive_commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,alive_commit), NULL, "COMMIT" },
+ { "alive-commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, alive_commit), NULL },
+ { "alive_commit", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, alive_commit), "COMMIT" },
- { "stop-begin", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,stop_begin), NULL, NULL },
- { "stop_begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,stop_begin), NULL, "START TRANSACTION" },
+ { "stop-begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, stop_begin), NULL },
+ { "stop_begin", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, stop_begin), "START TRANSACTION" },
- { "stop-clear", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,stop_clear), NULL, NULL },
- { "stop_clear", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED, offsetof(rlm_sqlippool_t,stop_clear), NULL, "" },
+ { "stop-clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, stop_clear), NULL },
+ { "stop_clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlippool_t, stop_clear), "" },
- { "stop-commit", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,stop_commit), NULL, NULL },
- { "stop_commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,stop_commit), NULL, "COMMIT" },
+ { "stop-commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, stop_commit), NULL },
+ { "stop_commit", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, stop_commit), "COMMIT" },
- { "on-begin", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,on_begin), NULL, NULL },
- { "on_begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,on_begin), NULL, "START TRANSACTION" },
+ { "on-begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, on_begin), NULL },
+ { "on_begin", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, on_begin), "START TRANSACTION" },
- { "on-clear", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,on_clear), NULL, NULL },
- { "on_clear", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED, offsetof(rlm_sqlippool_t,on_clear), NULL, "" },
+ { "on-clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, on_clear), NULL },
+ { "on_clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlippool_t, on_clear), "" },
- { "on-commit", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,on_commit), NULL, NULL },
- { "on_commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,on_commit), NULL, "COMMIT" },
+ { "on-commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, on_commit), NULL },
+ { "on_commit", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, on_commit), "COMMIT" },
- { "off-begin", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,off_begin), NULL, NULL },
- { "off_begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,off_begin), NULL, "START TRANSACTION" },
+ { "off-begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, off_begin), NULL },
+ { "off_begin", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, off_begin), "START TRANSACTION" },
- { "off-clear", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,off_clear), NULL, NULL },
- { "off_clear", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED, offsetof(rlm_sqlippool_t,off_clear), NULL, "" },
+ { "off-clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, off_clear), NULL },
+ { "off_clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlippool_t, off_clear), "" },
- { "off-commit",PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,off_commit), NULL, NULL },
- { "off_commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,off_commit), NULL, "COMMIT" },
+ { "off-commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, off_commit), NULL },
+ { "off_commit", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, off_commit), "COMMIT" },
- { "messages", PW_TYPE_SUBSECTION, 0, NULL, (void const *) message_config },
+ { "messages", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) message_config },
{ NULL, -1, 0, NULL, NULL }
};
break;
c = *p;
- if (c != '%' && c != '$' && c != '\\') {
+ if (c != '%') {
*q++ = *p;
continue;
}
- if (*++p == '\0')
+ if (*++p == '\0') {
break;
-
- if (c == '\\') {
- switch(*p) {
- case '\\':
- *q++ = '\\';
- break;
- case 't':
- *q++ = '\t';
- break;
- case 'n':
- *q++ = '\n';
- break;
- default:
- *q++ = c;
- *q++ = *p;
- break;
- }
}
- else if (c == '%') {
+
+ if (c == '%') {
switch(*p) {
- case '%':
- *q++ = *p;
- break;
case 'P': /* pool name */
strlcpy(q, data->pool_name, freespace);
q += strlen(q);
strlcpy(q, tmp, freespace);
q += strlen(q);
break;
+
default:
*q++ = '%';
*q++ = *p;
/*
* Query the database expecting a single result row
*/
-static int sqlippool_query1(char *out, int outlen, char const *fmt,
- rlm_sql_handle_t *handle, rlm_sqlippool_t *data,
- REQUEST *request, char *param, int param_len)
+static int CC_HINT(nonnull (1, 3, 4, 5)) sqlippool_query1(char *out, int outlen, char const *fmt,
+ rlm_sql_handle_t *handle, rlm_sqlippool_t *data,
+ REQUEST *request, char *param, int param_len)
{
char query[MAX_QUERY_LEN];
char *expanded = NULL;
*/
sqlippool_expand(query, sizeof(query), fmt, data, param, param_len);
- rad_assert(request != NULL);
-
*out = '\0';
/*
char const *pool_name = NULL;
pool_name = cf_section_name2(conf);
- if (pool_name != NULL)
- inst->pool_name = talloc_strdup(inst, pool_name);
- else
- inst->pool_name = talloc_strdup(inst, "ippool");
-
+ if (pool_name != NULL) {
+ inst->pool_name = talloc_typed_strdup(inst, pool_name);
+ } else {
+ inst->pool_name = talloc_typed_strdup(inst, "ippool");
+ }
sqlinst = find_module_instance(cf_section_find("modules"),
inst->sql_instance_name, 1);
if (!sqlinst) {
* If we have something to log, then we log it.
* Otherwise we return the retcode as soon as possible
*/
-static int do_logging(REQUEST *request, char *str, int rcode)
+static int do_logging(REQUEST *request, char const *str, int rcode)
{
char *expanded = NULL;
/*
* Allocate an IP number from the pool.
*/
-static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
{
rlm_sqlippool_t *inst = (rlm_sqlippool_t *) instance;
char allocation[MAX_STRING_LEN];
}
if (pairfind(request->config_items, PW_POOL_NAME, 0, TAG_ANY) == NULL) {
- RDEBUG("No Pool-Name defined.");
+ RDEBUG("No Pool-Name defined");
return do_logging(request, inst->log_nopool, RLM_MODULE_NOOP);
}
* sqlippool, so we should just ignore this
* allocation failure and return NOOP
*/
- RDEBUG("IP address could not be allocated as no pool exists with that name.");
+ RDEBUG("IP address could not be allocated as no pool exists with that name");
return RLM_MODULE_NOOP;
}
inst->sql_inst->sql_release_socket(inst->sql_inst, handle);
- RDEBUG("IP address could not be allocated.");
+ RDEBUG("IP address could not be allocated");
return do_logging(request, inst->log_failed, RLM_MODULE_NOOP);
}
/*
* FIXME: Make it work with the ipv6 addresses
*/
- if ((ip_hton(allocation, AF_INET, &ipaddr) < 0) ||
+ if ((ip_hton(&ipaddr, AF_INET, allocation, false) < 0) ||
((ip_allocation = ipaddr.ipaddr.ip4addr.s_addr) == INADDR_NONE)) {
DO(allocate_commit);
RDEBUG("Allocated IP %s [%08x]", allocation, ip_allocation);
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
PW_FRAMED_IP_ADDRESS, 0);
vp->vp_ipaddr = ip_allocation;
vp->length = 4;
* If we find one and we have allocated an IP to this nas/port
* combination, then deallocate it.
*/
-static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
{
int rcode = RLM_MODULE_NOOP;
VALUE_PAIR *vp;
vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY);
if (!vp) {
- RDEBUG("Could not find account status type in packet.");
+ RDEBUG("Could not find account status type in packet");
return RLM_MODULE_NOOP;
}
acct_status_type = vp->vp_integer;
--- /dev/null
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
+
+MAN := rlm_unbound.5
+
--- /dev/null
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
--- /dev/null
+#! /bin/sh
+# From configure.ac Revision.
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="rlm_unbound.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+targetname
+mod_ldflags
+mod_cflags
+CPP
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+if test x$with_rlm_unbound != xno; then
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+sm_lib_safe=`echo "unbound" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "ub_ctx_create" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+smart_lib=
+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 ub_ctx_create in -lunbound in $try" >&5
+$as_echo_n "checking for ub_ctx_create in -lunbound in $try... " >&6; }
+ LIBS="-L$try -lunbound $old_LIBS -Wl,-rpath,$try"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ub_ctx_create();
+int
+main ()
+{
+ub_ctx_create()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-L$try -lunbound -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"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ub_ctx_create in -lunbound" >&5
+$as_echo_n "checking for ub_ctx_create in -lunbound... " >&6; }
+ LIBS="-lunbound $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ub_ctx_create();
+int
+main ()
+{
+ub_ctx_create()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lunbound"
+ { $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=libunbound${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=libunbound.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 ub_ctx_create in -lunbound in $try" >&5
+$as_echo_n "checking for ub_ctx_create in -lunbound in $try... " >&6; }
+ LIBS="-L$try -lunbound $old_LIBS -Wl,-rpath,$try"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ub_ctx_create();
+int
+main ()
+{
+ub_ctx_create()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-L$try -lunbound -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"
+fi
+
+if test "x$smart_lib" != "x"; then
+ eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
+ LIBS="$smart_lib $old_LIBS"
+ SMART_LIBS="$smart_lib $SMART_LIBS"
+fi
+
+ if test "x$ac_cv_lib_unbound_ub_ctx_create" != "xyes"; then
+ fail="$fail libunbound"
+ fi
+
+
+
+ac_safe=`echo "unbound.h" | sed 'y%./+-%__pm%'`
+old_CFLAGS="$CFLAGS"
+smart_include=
+smart_include_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 unbound.h in $try" >&5
+$as_echo_n "checking for unbound.h in $try... " >&6; }
+ CFLAGS="$old_CFLAGS -isystem $try"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <unbound.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
+ CFLAGS="$old_CFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for unbound.h" >&5
+$as_echo_n "checking for unbound.h... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <unbound.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
+
+
+if test "x$LOCATE" != "x"; then
+ DIRS=
+ file=unbound.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 /usr/local/include /opt/include; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for unbound.h in $try" >&5
+$as_echo_n "checking for unbound.h in $try... " >&6; }
+ CFLAGS="$old_CFLAGS -isystem $try"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <unbound.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
+ CFLAGS="$old_CFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+ eval "ac_cv_header_$ac_safe=yes"
+ CFLAGS="$old_CFLAGS $smart_include"
+ SMART_CFLAGS="$SMART_CFLAGS $smart_include"
+fi
+
+ if test "$ac_cv_header_unbound_h" != "yes"; then
+ fail="$fail unbound.h"
+ fi
+
+
+
+ac_safe=`echo "openssl/crypto.h" | sed 'y%./+-%__pm%'`
+old_CFLAGS="$CFLAGS"
+smart_include=
+smart_include_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 openssl/crypto.h in $try" >&5
+$as_echo_n "checking for openssl/crypto.h in $try... " >&6; }
+ CFLAGS="$old_CFLAGS -isystem $try"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <openssl/crypto.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
+ CFLAGS="$old_CFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/crypto.h" >&5
+$as_echo_n "checking for openssl/crypto.h... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <openssl/crypto.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
+
+
+if test "x$LOCATE" != "x"; then
+ DIRS=
+ file=openssl/crypto.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 /usr/local/include /opt/include; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/crypto.h in $try" >&5
+$as_echo_n "checking for openssl/crypto.h in $try... " >&6; }
+ CFLAGS="$old_CFLAGS -isystem $try"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <openssl/crypto.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
+ CFLAGS="$old_CFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+ eval "ac_cv_header_$ac_safe=yes"
+ CFLAGS="$old_CFLAGS $smart_include"
+ SMART_CFLAGS="$SMART_CFLAGS $smart_include"
+fi
+
+ if test "$ac_cv_header_openssl_crypto_h" != "yes"; then
+ fail="$fail openssl/crypto.h"
+ fi
+
+ targetname=rlm_unbound
+else
+ targetname=
+ echo \*\*\* module rlm_unbound is disabled.
+fi
+
+if test x"$fail" != x""; then
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_unbound to disable it explicitly." "$LINENO" 5
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_unbound." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_unbound." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_unbound requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_unbound requires: $fail." >&2;};
+ targetname=""
+ fi
+fi
+
+mod_ldflags="${SMART_LIBS}"
+mod_cflags="${SMART_CFLAGS}"
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+
+
+ unset ac_cv_env_LIBS_set
+ unset ac_cv_env_LIBS_value
+
+ ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = "\a"
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_tt"; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = "\a"
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+ } >"$ac_tmp/config.h" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$ac_tmp/config.h" "$ac_file" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
+ fi
+ ;;
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
--- /dev/null
+AC_PREREQ([2.53])
+AC_INIT(rlm_unbound.c)
+AC_REVISION($Revision$)
+AC_DEFUN(modname,[rlm_unbound])
+
+if test x$with_[]modname != xno; then
+ AC_PROG_CC
+ AC_PROG_CPP
+
+ FR_SMART_CHECK_LIB(unbound, ub_ctx_create)
+ if test "x$ac_cv_lib_unbound_ub_ctx_create" != "xyes"; then
+ fail="$fail libunbound"
+ fi
+
+ FR_SMART_CHECK_INCLUDE(unbound.h)
+ if test "$ac_cv_header_unbound_h" != "yes"; then
+ fail="$fail unbound.h"
+ fi
+
+dnl # This needs work as libunbound could be using NSS or various other
+dnl # mixes of incompatible options and header/lib availability may occur.
+dnl # Since libunbound needs openssl locking set up, and may be
+dnl # linked against openssl even when we are not, play it safe.
+ FR_SMART_CHECK_INCLUDE(openssl/crypto.h)
+ if test "$ac_cv_header_openssl_crypto_h" != "yes"; then
+ fail="$fail openssl/crypto.h"
+ fi
+
+ targetname=modname
+else
+ targetname=
+ echo \*\*\* module modname is disabled.
+fi
+
+if test x"$fail" != x""; then
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ AC_MSG_ERROR([set --without-]modname[ to disable it explicitly.])
+ else
+ AC_MSG_WARN([silently not building ]modname[.])
+ AC_MSG_WARN([FAILURE: ]modname[ requires: $fail.]);
+ targetname=""
+ fi
+fi
+
+mod_ldflags="${SMART_LIBS}"
+mod_cflags="${SMART_CFLAGS}"
+
+AC_SUBST(mod_cflags)
+AC_SUBST(mod_ldflags)
+
+AC_CONFIG_HEADER(config.h)
+
+AC_SUBST(targetname)
+AC_OUTPUT(all.mk)
--- /dev/null
+.\" # DS - begin display
+.de DS
+.RS
+.nf
+.sp
+..
+.\" # DE - end display
+.de DE
+.fi
+.RE
+.sp
+..
+.TH rlm_unbound 5 "8 July 2013" "" "FreeRADIUS Module"
+.SH NAME
+rlm_unbound \- FreeRADIUS Module
+.SH DESCRIPTION
+Each instance of \fIrlm_unbound\fP provides an embedded DNS client
+for performing DNS lookups. Each instance may be configured separately
+to query different DNS horizons, change DNSSEC options, etc.
+.PP
+The module is primarily intended for use by other modules through
+internal APIs, and so, instances should be initialized earlier than
+those modules which use them. Each instance does also provide some
+xlat functionalities for general use and for troubleshooting.
+.PP
+Each instance of rlm_unbound may take the following parameters:
+.IP filename
+This file must exist and must point to a valid libunbound configuration file.
+The default is ${raddbdir}/mods-config/unbound/default.conf.
+.IP timeout
+While libunbound provides an asyncronous API for internal use, using any xlat
+is done syncronously from the perspective of unlang. This value limits the
+amount of time a request will wait for DNS to respond, after which the xlat
+will fail. The default is 3000 milliseconds. This setting is independent of
+any libunbound configuration values.
+.PP
+An instance named, for example, "dns" will provide the following xlat
+functionalities:
+.IP %{dns-a:<owner>}
+Performs an A lookup for the owner name, returning a stringified IPv4
+address. Only the first A record in the RRSET will be returned.
+.IP %{dns-aaaa:<owner>}
+Performs an AAAA lookup for the owner name, returning a stringified IPv6
+address. Only the first AAAA record in the RRSET will be returned.
+.IP %{dns-ptr:<owner>}
+Performs a PTR lookup for the owner.
+.PP
+.SH CAVEATS
+Logging from rlm_unbound can be problematic, especialy if more than one
+instantiation of the module is used. This is due to the need for additional
+features in the underlying libunbound which hopefully will be enhanced over
+time.
+.PP
+There is a potential for a FreeRADIUS server using rlm_unbound to either
+fail to terminate cleanly (leaving zombie processes, failing to clean up
+other modules, and hanging after a SIGTERM until a SIGKILL is sent) or
+to fail valgrind checks during termination when run with -m. Likewise this
+problem will rely on upstream enhancements before it can be fixed, and the
+exact behavior may change in interim releases until then.
+.PP
+The logging behavior of rlm_unbound may vary depending on whether
+FreeRADIUS is compiled with support for threads.
+.PP
+.SH FILES
+.I /etc/raddb/modules-available/rlm_unbound
+.I /etc/raddb/modules-config/unbound/
+.PP
+.SH "SEE ALSO"
+.BR radiusd (8),
+.BR radiusd.conf (5)
+.BR libunbound (3)
+.BR unbound.conf (5)
+.SH AUTHOR
+Brian S. Julin, bjulin@clarku.edu
+
--- /dev/null
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 if the
+ * License as published by the Free Software Foundation.
+ *
+ * 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
+ */
+
+/**
+ * $Id$
+ * @file rlm_unbound.c
+ * @brief DNS services via libunbound.
+ *
+ * @copyright 2013 The FreeRADIUS server project
+ * @copyright 2013 Brian S. Julin <bjulin@clarku.edu>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/log.h>
+#include <fcntl.h>
+#include <unbound.h>
+
+typedef struct rlm_unbound_t {
+ struct ub_ctx *ub; /* This must come first. Do not move */
+ fr_event_list_t *el; /* This must come second. Do not move. */
+
+ char const *name;
+ char const *xlat_a_name;
+ char const *xlat_aaaa_name;
+ char const *xlat_ptr_name;
+
+ uint32_t timeout;
+
+ char const *filename;
+
+ int log_fd;
+ FILE *log_stream;
+
+ int log_pipe[2];
+ FILE *log_pipe_stream[2];
+ bool log_pipe_in_use;
+} rlm_unbound_t;
+
+/*
+ * A mapping of configuration file names to internal variables.
+ */
+static const CONF_PARSER module_config[] = {
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_REQUIRED, rlm_unbound_t, filename), "${modconfdir}/unbound/default.conf" },
+ { "timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_unbound_t, timeout), "3000" },
+ { NULL, -1, 0, NULL, NULL } /* end the list */
+};
+
+/*
+ * Callback sent to libunbound for xlat functions. Simply links the
+ * new ub_result via a pointer that has been allocated from the heap.
+ * This pointer has been pre-initialized to a magic value.
+ */
+static void link_ubres(void* my_arg, int err, struct ub_result* result)
+{
+ struct ub_result **ubres = (struct ub_result **)my_arg;
+
+ /*
+ * Note that while result will be NULL on error, we are explicit
+ * here because that is actually a behavior that is suboptimal
+ * and only documented in the examples. It could change.
+ */
+ if (err) {
+ ERROR("rlm_unbound: %s", ub_strerror(err));
+ *ubres = NULL;
+ } else {
+ *ubres = result;
+ }
+}
+
+/*
+ * Convert labels as found in a DNS result to a NULL terminated string.
+ *
+ * Result is written to memory pointed to by "out" but no result will
+ * be written unless it and its terminating NULL character fit in "left"
+ * bytes. Returns the number of bytes written excluding the terminating
+ * NULL, or -1 if nothing was written because it would not fit or due
+ * to a violation in the labels format.
+ */
+static int rrlabels_tostr(char *out, char *rr, size_t left)
+{
+ int offset = 0;
+
+ /*
+ * TODO: verify that unbound results (will) always use this label
+ * format, and review the specs on this label format for nuances.
+ */
+
+ if (!left) {
+ return -1;
+ }
+ if (left > 253) {
+ left = 253; /* DNS length limit */
+ }
+ /* As a whole this should be "NULL terminated" by the 0-length label */
+ if (strnlen(rr, left) > left - 1) {
+ return -1;
+ }
+
+ /* It will fit, but does it it look well formed? */
+ while (1) {
+ size_t count;
+
+ count = *((unsigned char *)(rr + offset));
+ if (!count) break;
+
+ offset++;
+ if (count > 63 || strlen(rr + offset) < count) {
+ return -1;
+ }
+ offset += count;
+ }
+
+ /* Data is valid and fits. Copy it. */
+ offset = 0;
+ while (1) {
+ int count;
+
+ count = *((unsigned char *)(rr));
+ if (!count) break;
+
+ if (offset) {
+ *(out + offset) = '.';
+ offset++;
+ }
+
+ rr++;
+ memcpy(out + offset, rr, count);
+ rr += count;
+ offset += count;
+ }
+
+ *(out + offset) = '\0';
+ return offset;
+}
+
+static int ub_common_wait(rlm_unbound_t *inst, REQUEST *request, char const *tag, struct ub_result **ub, int async_id)
+{
+ useconds_t iv, waited;
+
+ iv = inst->timeout > 64 ? 64000 : inst->timeout * 1000;
+ ub_process(inst->ub);
+
+ for (waited = 0; (void*)*ub == (void *)inst; waited += iv, iv += iv) {
+
+ if (waited + iv > (useconds_t)inst->timeout * 1000) {
+ usleep(inst->timeout * 1000 - waited);
+ ub_process(inst->ub);
+ break;
+ }
+
+ usleep(iv);
+
+ /* Check if already handled by event loop */
+ if ((void *)*ub != (void *)inst) {
+ break;
+ }
+
+ /* In case we are running single threaded */
+ ub_process(inst->ub);
+ }
+
+ if ((void *)*ub == (void *)inst) {
+ int res;
+
+ RDEBUG("rlm_unbound (%s): DNS took too long", tag);
+
+ res = ub_cancel(inst->ub, async_id);
+ if (res) {
+ REDEBUG("rlm_unbound (%s): ub_cancel: %s",
+ tag, ub_strerror(res));
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ub_common_fail(REQUEST *request, char const *tag, struct ub_result *ub)
+{
+ if (ub->bogus) {
+ RWDEBUG("rlm_unbound (%s): Bogus DNS response", tag);
+ return -1;
+ }
+
+ if (ub->nxdomain) {
+ RDEBUG("rlm_unbound (%s): NXDOMAIN", tag);
+ return -1;
+ }
+
+ if (!ub->havedata) {
+ RDEBUG("rlm_unbound (%s): empty result", tag);
+ return -1;
+ }
+
+ return 0;
+}
+
+static ssize_t xlat_a(void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
+{
+ rlm_unbound_t *inst = instance;
+ struct ub_result **ubres;
+ int async_id;
+ char *fmt2; /* For const warnings. Keep till new libunbound ships. */
+
+ /* This has to be on the heap, because threads. */
+ ubres = talloc(inst, struct ub_result *);
+
+ /* Used and thus impossible value from heap to designate incomplete */
+ *ubres = (void *)instance;
+
+ fmt2 = talloc_typed_strdup(inst, fmt);
+ ub_resolve_async(inst->ub, fmt2, 1, 1, ubres, link_ubres, &async_id);
+ talloc_free(fmt2);
+
+ if (ub_common_wait(inst, request, inst->xlat_a_name, ubres, async_id)) {
+ goto error0;
+ }
+
+ if (*ubres) {
+ if (ub_common_fail(request, inst->xlat_a_name, *ubres)) {
+ goto error1;
+ }
+
+ if (!inet_ntop(AF_INET, (*ubres)->data[0], out, freespace)) {
+ goto error1;
+ };
+
+ ub_resolve_free(*ubres);
+ talloc_free(ubres);
+ return strlen(out);
+ }
+
+ RWDEBUG("rlm_unbound (%s): no result", inst->xlat_a_name);
+
+ error1:
+ ub_resolve_free(*ubres); /* Handles NULL gracefully */
+
+ error0:
+ talloc_free(ubres);
+ return -1;
+}
+
+static ssize_t xlat_aaaa(void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
+{
+ rlm_unbound_t *inst = instance;
+ struct ub_result **ubres;
+ int async_id;
+ char *fmt2; /* For const warnings. Keep till new libunbound ships. */
+
+ /* This has to be on the heap, because threads. */
+ ubres = talloc(inst, struct ub_result *);
+
+ /* Used and thus impossible value from heap to designate incomplete */
+ *ubres = (void *)instance;
+
+ fmt2 = talloc_typed_strdup(inst, fmt);
+ ub_resolve_async(inst->ub, fmt2, 28, 1, ubres, link_ubres, &async_id);
+ talloc_free(fmt2);
+
+ if (ub_common_wait(inst, request, inst->xlat_aaaa_name, ubres, async_id)) {
+ goto error0;
+ }
+
+ if (*ubres) {
+ if (ub_common_fail(request, inst->xlat_aaaa_name, *ubres)) {
+ goto error1;
+ }
+ if (!inet_ntop(AF_INET6, (*ubres)->data[0], out, freespace)) {
+ goto error1;
+ };
+ ub_resolve_free(*ubres);
+ talloc_free(ubres);
+ return strlen(out);
+ }
+
+ RWDEBUG("rlm_unbound (%s): no result", inst->xlat_aaaa_name);
+
+error1:
+ ub_resolve_free(*ubres); /* Handles NULL gracefully */
+
+error0:
+ talloc_free(ubres);
+ return -1;
+}
+
+static ssize_t xlat_ptr(void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
+{
+ rlm_unbound_t *inst = instance;
+ struct ub_result **ubres;
+ int async_id;
+ char *fmt2; /* For const warnings. Keep till new libunbound ships. */
+
+ /* This has to be on the heap, because threads. */
+ ubres = talloc(inst, struct ub_result *);
+
+ /* Used and thus impossible value from heap to designate incomplete */
+ *ubres = (void *)instance;
+
+ fmt2 = talloc_typed_strdup(inst, fmt);
+ ub_resolve_async(inst->ub, fmt2, 12, 1, ubres, link_ubres, &async_id);
+ talloc_free(fmt2);
+
+ if (ub_common_wait(inst, request, inst->xlat_ptr_name,
+ ubres, async_id)) {
+ goto error0;
+ }
+
+ if (*ubres) {
+ if (ub_common_fail(request, inst->xlat_ptr_name, *ubres)) {
+ goto error1;
+ }
+ if (rrlabels_tostr(out, (*ubres)->data[0], freespace) < 0) {
+ goto error1;
+ }
+ ub_resolve_free(*ubres);
+ talloc_free(ubres);
+ return strlen(out);
+ }
+
+ RWDEBUG("rlm_unbound (%s): no result", inst->xlat_ptr_name);
+
+error1:
+ ub_resolve_free(*ubres); /* Handles NULL gracefully */
+
+error0:
+ talloc_free(ubres);
+ return -1;
+}
+
+/*
+ * Even when run in asyncronous mode, callbacks sent to libunbound still
+ * must be run in an application-side thread (via ub_process.) This is
+ * probably to keep the API usage consistent across threaded and forked
+ * embedded client modes. This callback function lets an event loop call
+ * ub_process when the instance's file descriptor becomes ready.
+ */
+static void ub_fd_handler(UNUSED fr_event_list_t *el, UNUSED int sock, void *ctx)
+{
+ rlm_unbound_t *inst = ctx;
+ int err;
+
+ err = ub_process(inst->ub);
+ if (err) {
+ ERROR("rlm_unbound (%s) async ub_process: %s",
+ inst->name, ub_strerror(err));
+ }
+}
+
+#ifndef HAVE_PTHREAD_H
+
+/* If we have to use a pipe to redirect logging, this does the work. */
+static void log_spew(UNUSED fr_event_list_t *el, UNUSED int sock, void *ctx)
+{
+ rlm_unbound_t *inst = ctx;
+ char line[1024];
+
+ /*
+ * This works for pipes from processes, but not from threads
+ * right now. The latter is hinky and will require some fancy
+ * blocking/nonblocking trickery which is not figured out yet,
+ * since selecting on a pipe from a thread in the same process
+ * seems to behave differently. It will likely preclude the use
+ * of fgets and streams. Left for now since some unbound logging
+ * infrastructure is still global across multiple contexts. Maybe
+ * we can get unbound folks to provide a ub_ctx_debugout_async that
+ * takes a function hook instead to just bypass the piping when
+ * used in threaded mode.
+ */
+ while (fgets(line, 1024, inst->log_pipe_stream[0])) {
+ DEBUG("rlm_unbound (%s): %s", inst->name, line);
+ }
+}
+
+#endif
+
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ rlm_unbound_t *inst = instance;
+ int res;
+ char *optval;
+
+ log_dst_t log_dst;
+ int log_level;
+ int log_fd = -1;
+
+ char k[64]; /* To silence const warns until newer unbound in distros */
+
+ inst->el = radius_event_list_corral(EVENT_CORRAL_AUX);
+ inst->log_pipe_stream[0] = NULL;
+ inst->log_pipe_stream[1] = NULL;
+ inst->log_fd = -1;
+ inst->log_pipe_in_use = false;
+
+ inst->name = cf_section_name2(conf);
+ if (!inst->name) {
+ inst->name = cf_section_name1(conf);
+ }
+
+ if (inst->timeout > 10000) {
+ ERROR("rlm_unbound (%s): timeout must be 0 to 10000", inst->name);
+ return -1;
+ }
+
+ inst->ub = ub_ctx_create();
+ if (!inst->ub) {
+ ERROR("rlm_unbound (%s): ub_ctx_create failed", inst->name);
+ return -1;
+ }
+
+#ifdef HAVE_PTHREAD_H
+ /*
+ * Note unbound threads WILL happen with -s option, if it matters.
+ * We cannot tell from here whether that option is in effect.
+ */
+ res = ub_ctx_async(inst->ub, 1);
+#else
+ /*
+ * Uses forked subprocesses instead.
+ */
+ res = ub_ctx_async(inst->ub, 0);
+#endif
+
+ if (res) goto error;
+
+ /* Glean some default settings to match the main server. */
+ /* TODO: debug_level can be changed at runtime. */
+ /* TODO: log until fork when stdout or stderr and !debug_flag. */
+ log_level = 0;
+
+ if (debug_flag > 0) {
+ log_level = debug_flag;
+
+ } else if (main_config.debug_level > 0) {
+ log_level = main_config.debug_level;
+ }
+
+ switch (log_level) {
+ /* TODO: This will need some tweaking */
+ case 0:
+ case 1:
+ break;
+
+ case 2:
+ log_level = 1;
+ break;
+
+ case 3:
+ case 4:
+ log_level = 2; /* mid-to-heavy levels of output */
+ break;
+
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ log_level = 3; /* Pretty crazy amounts of output */
+ break;
+
+ default:
+ log_level = 4; /* Insane amounts of output including crypts */
+ break;
+ }
+
+ res = ub_ctx_debuglevel(inst->ub, log_level);
+ if (res) goto error;
+
+ switch(default_log.dst) {
+ case L_DST_STDOUT:
+ if (!debug_flag) {
+ log_dst = L_DST_NULL;
+ break;
+ }
+ log_dst = L_DST_STDOUT;
+ log_fd = dup(STDOUT_FILENO);
+ break;
+
+ case L_DST_STDERR:
+ if (!debug_flag) {
+ log_dst = L_DST_NULL;
+ break;
+ }
+ log_dst = L_DST_STDOUT;
+ log_fd = dup(STDERR_FILENO);
+ break;
+
+ case L_DST_FILES:
+ if (main_config.log_file) {
+ char *log_file;
+
+ strcpy(k, "logfile:");
+ /* 3rd argument isn't const'd in libunbounds API */
+ memcpy(&log_file, &main_config.log_file, sizeof(log_file));
+ res = ub_ctx_set_option(inst->ub, k, log_file);
+ if (res) {
+ goto error;
+ }
+ log_dst = L_DST_FILES;
+ break;
+ }
+ /* FALL-THROUGH */
+
+ case L_DST_NULL:
+ log_dst = L_DST_NULL;
+ break;
+
+ default:
+ log_dst = L_DST_SYSLOG;
+ break;
+ }
+
+ /* Now load the config file, which can override gleaned settings. */
+ {
+ char *file;
+
+ memcpy(&file, &inst->filename, sizeof(file));
+ res = ub_ctx_config(inst->ub, file);
+ if (res) goto error;
+ }
+
+ /*
+ * Check if the config file tried to use syslog. Unbound
+ * does not share syslog gracefully.
+ */
+ strcpy(k, "use-syslog");
+ res = ub_ctx_get_option(inst->ub, k, &optval);
+ if (res || !optval) goto error;
+
+ if (!strcmp(optval, "yes")) {
+ char v[3];
+
+ free(optval);
+
+ WARN("rlm_unbound (%s): Overriding syslog settings.", inst->name);
+ strcpy(k, "use-syslog:");
+ strcpy(v, "no");
+ res = ub_ctx_set_option(inst->ub, k, v);
+ if (res) goto error;
+
+ if (log_dst == L_DST_FILES) {
+ char *log_file;
+
+ /* Reinstate the log file name JIC */
+ strcpy(k, "logfile:");
+ /* 3rd argument isn't const'd in libunbounds API */
+ memcpy(&log_file, &main_config.log_file, sizeof(log_file));
+ res = ub_ctx_set_option(inst->ub, k, log_file);
+ if (res) goto error;
+ }
+
+ } else {
+ if (optval) free(optval);
+ strcpy(k, "logfile");
+
+ res = ub_ctx_get_option(inst->ub, k, &optval);
+ if (res) goto error;
+
+ if (optval && strlen(optval)) {
+ log_dst = L_DST_FILES;
+
+ } else if (!debug_flag) {
+ log_dst = L_DST_NULL;
+ }
+
+ if (optval) free(optval);
+ }
+
+ switch (log_dst) {
+ case L_DST_STDOUT:
+ /*
+ * We have an fd to log to. And we've already attempted to
+ * dup it so libunbound doesn't close it on us.
+ */
+ if (log_fd == -1) {
+ ERROR("rlm_unbound (%s): Could not dup fd", inst->name);
+ goto error_nores;
+ }
+
+ inst->log_stream = fdopen(log_fd, "w");
+ if (!inst->log_stream) {
+ ERROR("rlm_unbound (%s): error setting up log stream", inst->name);
+ goto error_nores;
+ }
+
+ res = ub_ctx_debugout(inst->ub, inst->log_stream);
+ if (res) goto error;
+ break;
+
+ case L_DST_FILES:
+ /* We gave libunbound a filename. It is on its own now. */
+ break;
+
+ case L_DST_NULL:
+ /* We tell libunbound not to log at all. */
+ res = ub_ctx_debugout(inst->ub, NULL);
+ if (res) goto error;
+ break;
+
+ case L_DST_SYSLOG:
+#ifdef HAVE_PTHREAD_H
+ /*
+ * Currently this wreaks havoc when running threaded, so just
+ * turn logging off until that gets figured out.
+ */
+ res = ub_ctx_debugout(inst->ub, NULL);
+ if (res) goto error;
+ break;
+#else
+ /*
+ * We need to create a pipe, because libunbound does not
+ * share syslog nicely. Or the core added some new logsink.
+ */
+ if (pipe(inst->log_pipe)) {
+ error_pipe:
+ ERROR("rlm_unbound (%s): Error setting up log pipes", inst->name);
+ goto error_nores;
+ }
+
+ if ((fcntl(inst->log_pipe[0], F_SETFL, O_NONBLOCK) < 0) ||
+ (fcntl(inst->log_pipe[0], F_SETFD, FD_CLOEXEC) < 0)) {
+ goto error_pipe;
+ }
+
+ /* Opaque to us when this can be closed, so we do not. */
+ if (fcntl(inst->log_pipe[1], F_SETFL, O_NONBLOCK) < 0) {
+ goto error_pipe;
+ }
+
+ inst->log_pipe_stream[0] = fdopen(inst->log_pipe[0], "r");
+ inst->log_pipe_stream[1] = fdopen(inst->log_pipe[1], "w");
+
+ if (!inst->log_pipe_stream[0] || !inst->log_pipe_stream[1]) {
+ if (!inst->log_pipe_stream[1]) {
+ close(inst->log_pipe[1]);
+ }
+
+ if (!inst->log_pipe_stream[0]) {
+ close(inst->log_pipe[0]);
+ }
+ ERROR("rlm_unbound (%s): Error setting up log stream", inst->name);
+ goto error_nores;
+ }
+
+ res = ub_ctx_debugout(inst->ub, inst->log_pipe_stream[1]);
+ if (res) goto error;
+
+ if (!fr_event_fd_insert(inst->el, 0, inst->log_pipe[0], log_spew, inst)) {
+ ERROR("rlm_unbound (%s): could not insert log fd", inst->name);
+ goto error_nores;
+ }
+
+ inst->log_pipe_in_use = true;
+#endif
+ default:
+ break;
+ }
+
+ /*
+ * Now we need to finalize the context.
+ *
+ * There's no clean API to just finalize the context made public
+ * in libunbound. But we can trick it by trying to delete data
+ * which as it happens fails quickly and quietly even though the
+ * data did not exist.
+ */
+ strcpy(k, "notar33lsite.foo123.nottld A 127.0.0.1");
+ ub_ctx_data_remove(inst->ub, k);
+
+ inst->log_fd = ub_fd(inst->ub);
+ if (inst->log_fd >= 0) {
+ if (!fr_event_fd_insert(inst->el, 0, inst->log_fd, ub_fd_handler, inst)) {
+ ERROR("rlm_unbound (%s): could not insert async fd", inst->name);
+ inst->log_fd = -1;
+ goto error_nores;
+ }
+
+ }
+
+ MEM(inst->xlat_a_name = talloc_typed_asprintf(inst, "%s-a", inst->name));
+ MEM(inst->xlat_aaaa_name = talloc_typed_asprintf(inst, "%s-aaaa", inst->name));
+ MEM(inst->xlat_ptr_name = talloc_typed_asprintf(inst, "%s-ptr", inst->name));
+
+ if (xlat_register(inst->xlat_a_name, xlat_a, NULL, inst) ||
+ xlat_register(inst->xlat_aaaa_name, xlat_aaaa, NULL, inst) ||
+ xlat_register(inst->xlat_ptr_name, xlat_ptr, NULL, inst)) {
+ ERROR("rlm_unbound (%s): Failed registering xlats", inst->name);
+ xlat_unregister(inst->xlat_a_name, xlat_a, inst);
+ xlat_unregister(inst->xlat_aaaa_name, xlat_aaaa, inst);
+ xlat_unregister(inst->xlat_ptr_name, xlat_ptr, inst);
+ goto error_nores;
+ }
+ return 0;
+
+ error:
+ ERROR("rlm_unbound (%s): %s", inst->name, ub_strerror(res));
+
+ error_nores:
+ if (log_fd > -1) close(log_fd);
+
+ return -1;
+}
+
+static int mod_detach(UNUSED void *instance)
+{
+ rlm_unbound_t *inst = instance;
+
+ xlat_unregister(inst->xlat_a_name, xlat_a, inst);
+ xlat_unregister(inst->xlat_aaaa_name, xlat_aaaa, inst);
+ xlat_unregister(inst->xlat_ptr_name, xlat_ptr, inst);
+
+ if (inst->log_fd >= 0) {
+ fr_event_fd_delete(inst->el, 0, inst->log_fd);
+ if (inst->ub) {
+ ub_process(inst->ub);
+ /* This can hang/leave zombies currently
+ * see upstream bug #519
+ * ...so expect valgrind to complain with -m
+ */
+#if 0
+ ub_ctx_delete(inst->ub);
+#endif
+ }
+ }
+
+ if (inst->log_pipe_stream[1]) {
+ fclose(inst->log_pipe_stream[1]);
+ }
+
+ if (inst->log_pipe_stream[0]) {
+ if (inst->log_pipe_in_use) {
+ fr_event_fd_delete(inst->el, 0, inst->log_pipe[0]);
+ }
+ fclose(inst->log_pipe_stream[0]);
+ }
+
+ if (inst->log_stream) {
+ fclose(inst->log_stream);
+ }
+
+ return 0;
+}
+
+module_t rlm_unbound = {
+ RLM_MODULE_INIT,
+ "unbound",
+ RLM_TYPE_THREAD_SAFE, /* type */
+ sizeof(rlm_unbound_t),
+ module_config,
+ mod_instantiate, /* instantiation */
+ mod_detach, /* detach */
+ /* This module does not directly interact with requests */
+ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+};
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
CPP C preprocessor
Use these variables to override the choices made by `configure' or to help
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no getpwnam" >&5
$as_echo "no getpwnam" >&6; }
fail=$fail" getpwnam"
- fi
+ fi
if test "$ac_cv_header_pwd_h" != "yes"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no pwd.h" >&5
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
--header=FILE[:TEMPLATE]
- instantiate the configuration header FILE
+ instantiate the configuration header FILE
Configuration files:
$config_files
if test "$ac_cv_func_getpwnam" != "yes"; then
AC_MSG_RESULT(no getpwnam)
[ fail=$fail" getpwnam" ]
- fi
+ fi
if test "$ac_cv_header_pwd_h" != "yes"; then
AC_MSG_RESULT(no pwd.h)
#define ENC(c) trans[c]
struct unix_instance {
+ char const *name; //!< Instance name.
char const *radwtmp;
};
static const CONF_PARSER module_config[] = {
- { "radwtmp", PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED,
- offsetof(struct unix_instance,radwtmp), NULL, "NULL" },
+ { "radwtmp", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED, struct unix_instance, radwtmp), "NULL" },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
{
struct unix_instance *inst = instance;
+ DICT_ATTR const *group_da, *user_name_da;
+
+ inst->name = cf_section_name2(conf);
+ if (!inst->name) {
+ inst->name = cf_section_name1(conf);
+ }
+
+ group_da = dict_attrbyvalue(PW_GROUP, 0);
+ if (!group_da) {
+ ERROR("rlm_unix (%s): 'Group' attribute not found in dictionary", inst->name);
+ return -1;
+ }
+
+ user_name_da = dict_attrbyvalue(PW_USER_NAME, 0);
+ if (!user_name_da) {
+ ERROR("rlm_unix (%s): 'User-Name' attribute not found in dictionary", inst->name);
+ return -1;
+ }
/* FIXME - delay these until a group file has been read so we know
* groupcmp can actually do something */
- paircompare_register(dict_attrbyvalue(PW_GROUP, 0), dict_attrbyvalue(PW_USER_NAME, 0), false, groupcmp, inst);
+ paircompare_register(group_da, user_name_da, false, groupcmp, inst);
#ifdef PW_GROUP_NAME /* compat */
- paircompare_register(dict_attrbyvalue(PW_GROUP_NAME, 0), dict_attrbyvalue(PW_USER_NAME, 0),
- true, groupcmp, inst);
+ {
+ DICT_ATTR const *group_name_da;
+
+ group_name_da = dict_attrbyvalue(PW_GROUP_NAME, 0);
+ if (!group_name_da) {
+ ERROR("rlm_unix (%s): 'Group-Name' attribute not found in dictionary", inst->name);
+ return -1;
+ }
+ paircompare_register(group_name_da, user_name_da, true, groupcmp, inst);
+ }
#endif
return 0;
* Pull the users password from where-ever, and add it to
* the given vp list.
*/
-static rlm_rcode_t mod_authorize(UNUSED void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, REQUEST *request)
{
char const *name;
char const *encrypted_pass;
/*
* Unix accounting - write a wtmp file.
*/
-static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
{
VALUE_PAIR *vp;
vp_cursor_t cursor;
#ifdef USER_PROCESS
int protocol = -1;
#endif
- int nas_port = 0;
- int port_seen = 0;
+ uint32_t nas_port = 0;
+ bool port_seen = true;
struct unix_instance *inst = (struct unix_instance *) instance;
/*
* No radwtmp. Don't do anything.
*/
if (!inst->radwtmp) {
- RDEBUG2("No radwtmp file configured. Ignoring accounting request.");
+ RDEBUG2("No radwtmp file configured. Ignoring accounting request");
return RLM_MODULE_NOOP;
}
* Which type is this.
*/
if ((vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY))==NULL) {
- RDEBUG("no Accounting-Status-Type attribute in request.");
+ RDEBUG("no Accounting-Status-Type attribute in request");
return RLM_MODULE_NOOP;
}
status = vp->vp_integer;
/*
* First, find the interesting attributes.
*/
- for (vp = paircursor(&cursor, &request->packet->vps);
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
if (!vp->da->vendor) switch (vp->da->attr) {
case PW_USER_NAME:
if (vp->length >= sizeof(ut.ut_name)) {
break;
case PW_NAS_PORT:
nas_port = vp->vp_integer;
- port_seen = 1;
+ port_seen = true;
break;
case PW_ACCT_DELAY_TIME:
delay = vp->vp_ipaddr;
module_t rlm_unix = {
RLM_MODULE_INIT,
"System",
- RLM_TYPE_THREAD_UNSAFE | RLM_TYPE_CHECK_CONFIG_SAFE,
+ RLM_TYPE_THREAD_UNSAFE,
sizeof(struct unix_instance),
module_config,
mod_instantiate, /* instantiation */
--- /dev/null
+TARGET := rlm_unpack.a
+SOURCES := rlm_unpack.c
--- /dev/null
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 if the
+ * License as published by the Free Software Foundation.
+ *
+ * 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
+ */
+
+/**
+ * $Id$
+ * @file rlm_unpack.c
+ * @brief Unpack binary data
+ *
+ * @copyright 2014 The FreeRADIUS server project
+ * @copyright 2014 Alan DeKok <aland@freeradius.org>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <ctype.h>
+
+#define PW_CAST_BASE (1850)
+
+#define GOTO_ERROR do { REDEBUG("Unexpected text at '%s'", p); goto error;} while (0)
+
+/** Unpack data
+ *
+ * Example: %{unpack:&Class 0 integer}
+ *
+ * Expands Class, treating octet at offset 0 (bytes 0-3) as an "integer".
+ */
+static ssize_t unpack_xlat(UNUSED void *instance, REQUEST *request, char const *fmt,
+ char *out, size_t outlen)
+{
+ char *data_name, *data_size, *data_type;
+ char *p;
+ size_t len, input_len;
+ int offset;
+ PW_TYPE type;
+ DICT_ATTR const *da;
+ VALUE_PAIR *vp, *cast;
+ uint8_t const *input;
+ char buffer[256];
+ uint8_t blob[256];
+
+ /*
+ * FIXME: copy only the fields here, as we parse them.
+ */
+ strlcpy(buffer, fmt, sizeof(buffer));
+
+ p = buffer;
+ while (isspace((int) *p)) p++; /* skip leading spaces */
+
+ data_name = p;
+
+ while (*p && !isspace((int) *p)) p++;
+
+ if (!*p) {
+ error:
+ REDEBUG("Format string should be '<data> <offset> <type>' e.g. '&Class 1 integer'");
+ nothing:
+ *out = '\0';
+ return -1;
+ }
+
+ while (isspace((int) *p)) *(p++) = '\0';
+ if (!*p) GOTO_ERROR;
+
+ data_size = p;
+
+ while (*p && !isspace((int) *p)) p++;
+ if (!*p) GOTO_ERROR;
+
+ while (isspace((int) *p)) *(p++) = '\0';
+ if (!*p) GOTO_ERROR;
+
+ data_type = p;
+
+ while (*p && !isspace((int) *p)) p++;
+ if (*p) GOTO_ERROR; /* anything after the type is an error */
+
+ /*
+ * Attribute reference
+ */
+ if (*data_name == '&') {
+ if (radius_get_vp(&vp, request, data_name) < 0) goto nothing;
+
+ if ((vp->da->type != PW_TYPE_OCTETS) &&
+ (vp->da->type != PW_TYPE_STRING)) {
+ REDEBUG("unpack requires the input attribute to be 'string' or 'octets'");
+ goto nothing;
+ }
+ input = vp->vp_octets;
+ input_len = vp->length;
+
+ } else if ((data_name[0] == '0') && (data_name[1] == 'x')) {
+ /*
+ * Hex data.
+ */
+ len = strlen(data_name + 2);
+ if ((len & 0x01) != 0) {
+ RDEBUG("Invalid hex string in '%s'", data_name);
+ goto nothing;
+ }
+ input = blob;
+ input_len = fr_hex2bin(blob, data_name + 2, sizeof(blob));
+
+ } else {
+ GOTO_ERROR;
+ }
+
+ offset = (int) strtoul(data_size, &p, 10);
+ if (*p) {
+ REDEBUG("unpack requires a decimal number, not '%s'", data_size);
+ goto nothing;
+ }
+
+ type = fr_str2int(dict_attr_types, data_type, PW_TYPE_INVALID);
+ if (type == PW_TYPE_INVALID) {
+ REDEBUG("Invalid data type '%s'", data_type);
+ goto nothing;
+ }
+
+ /*
+ * Output must be a non-zero limited size.
+ */
+ if ((dict_attr_sizes[type][0] == 0) ||
+ (dict_attr_sizes[type][0] != dict_attr_sizes[type][1])) {
+ REDEBUG("unpack requires fixed-size output type, not '%s'", data_type);
+ goto nothing;
+ }
+
+ if (input_len < (offset + dict_attr_sizes[type][0])) {
+ REDEBUG("Insufficient data to unpack '%s' from '%s'", data_type, data_name);
+ goto nothing;
+ }
+
+ da = dict_attrbyvalue(PW_CAST_BASE + type, 0);
+ if (!da) {
+ REDEBUG("Cannot decode type '%s'", data_type);
+ goto nothing;
+ }
+
+ cast = pairalloc(request, da);
+ if (!cast) goto nothing;
+
+ memcpy(&(cast->data), input + offset, dict_attr_sizes[type][0]);
+ cast->length = dict_attr_sizes[type][0];
+
+ /*
+ * Hacks
+ */
+ switch (type) {
+ case PW_TYPE_SIGNED:
+ case PW_TYPE_INTEGER:
+ case PW_TYPE_DATE:
+ cast->vp_integer = ntohl(cast->vp_integer);
+ break;
+
+ case PW_TYPE_SHORT:
+ cast->vp_short = ((input[offset] << 8) | input[offset + 1]);
+ break;
+
+ case PW_TYPE_INTEGER64:
+ cast->vp_integer64 = ntohll(cast->vp_integer64);
+ break;
+
+ default:
+ break;
+ }
+
+ len = vp_prints_value(out, outlen, cast, 0);
+ talloc_free(cast);
+ if (is_truncated(len, outlen)) {
+ REDEBUG("Insufficient buffer space to unpack data");
+ goto nothing;
+ }
+
+ return len;
+}
+
+
+/*
+ * Register the xlats
+ */
+static int mod_instantiate(UNUSED CONF_SECTION *conf, void *instance)
+{
+ xlat_register("unpack", unpack_xlat, NULL, instance);
+
+ return 0;
+}
+
+/*
+ * The module name should be the only globally exported symbol.
+ * That is, everything else should be 'static'.
+ *
+ * If the module needs to temporarily modify it's instantiation
+ * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
+ * The server will then take care of ensuring that the module
+ * is single-threaded.
+ */
+module_t rlm_unpack = {
+ RLM_MODULE_INIT,
+ "unpack",
+ RLM_TYPE_THREAD_SAFE, /* type */
+ 0,
+ NULL,
+ mod_instantiate, /* instantiation */
+ NULL, /* detach */
+ {
+ NULL, /* authentication */
+ NULL, /* authorization */
+ NULL, NULL, NULL,
+ NULL, /* pre-proxy */
+ NULL, /* post-proxy */
+ NULL /* post-auth */
+ },
+};
/*
* Reject any non-UTF8 data.
*/
-static rlm_rcode_t utf8_clean(UNUSED void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_utf8_clean(UNUSED void *instance, REQUEST *request)
{
size_t i, len;
VALUE_PAIR *vp;
vp_cursor_t cursor;
- for (vp = paircursor(&cursor, &request->packet->vps);
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
vp;
- vp = pairnext(&cursor)) {
+ vp = fr_cursor_next(&cursor)) {
if (vp->da->type != PW_TYPE_STRING) continue;
for (i = 0; i < vp->length; i += len) {
NULL, /* detach */
{
NULL, /* authentication */
- utf8_clean, /* authorization */
- utf8_clean, /* preaccounting */
+ mod_utf8_clean, /* authorization */
+ mod_utf8_clean, /* preaccounting */
NULL, /* accounting */
NULL, /* checksimul */
NULL, /* pre-proxy */
NULL, /* post-proxy */
NULL /* post-auth */
#ifdef WITH_COA
- , utf8_clean,
+ , mod_utf8_clean,
NULL
#endif
},
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
CPP C preprocessor
Use these variables to override the choices made by `configure' or to help
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
Configuration files:
$config_files
* buffer over-flows.
*/
static const CONF_PARSER module_config[] = {
- { "delete_mppe_keys", PW_TYPE_BOOLEAN,
- offsetof(rlm_wimax_t,delete_mppe_keys), NULL, "no" },
+ { "delete_mppe_keys", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_wimax_t, delete_mppe_keys), "no" },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
* from the database. The authentication code only needs to check
* the password, the rest is done here.
*/
-static rlm_rcode_t mod_authorize(UNUSED void *instance, UNUSED REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, UNUSED REQUEST *request)
{
VALUE_PAIR *vp;
DEBUG2("rlm_wimax: Fixing WiMAX binary Calling-Station-Id to %s",
vp->vp_strvalue);
+ return RLM_MODULE_OK;
}
- return RLM_MODULE_OK;
+ return RLM_MODULE_NOOP;
}
/*
* Massage the request before recording it or proxying it
*/
-static rlm_rcode_t mod_preacct(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_preacct(void *instance, REQUEST *request)
{
return mod_authorize(instance, request);
}
/*
* Write accounting information to this modules database.
*/
-static rlm_rcode_t mod_accounting(UNUSED void *instance, UNUSED REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(UNUSED void *instance, UNUSED REQUEST *request)
{
return RLM_MODULE_OK;
}
/*
* Generate the keys after the user has been authenticated.
*/
-static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
{
rlm_wimax_t *inst = instance;
VALUE_PAIR *msk, *emsk, *vp;
msk = pairfind(request->reply->vps, 1129, 0, TAG_ANY);
emsk = pairfind(request->reply->vps, 1130, 0, TAG_ANY);
if (!msk || !emsk) {
- RDEBUG("No EAP-MSK or EAP-EMSK. Cannot create WiMAX keys.");
+ RDEBUG("No EAP-MSK or EAP-EMSK. Cannot create WiMAX keys");
return RLM_MODULE_NOOP;
}
mn_nai = pairfind(request->packet->vps, 1900, 0, TAG_ANY);
if (!mn_nai) mn_nai = pairfind(request->reply->vps, 1900, 0, TAG_ANY);
if (!mn_nai) {
- RWDEBUG("WiMAX-MN-NAI was not found in the request or in the reply.");
- RWDEBUG("We cannot calculate MN-HA keys.");
+ RWDEBUG("WiMAX-MN-NAI was not found in the request or in the reply");
+ RWDEBUG("We cannot calculate MN-HA keys");
}
/*
vp = NULL;
if (mn_nai) vp = pairfind(request->reply->vps, 23, VENDORPEC_WIMAX, TAG_ANY);
if (!vp) {
- RWDEBUG("WiMAX-IP-Technology not found in reply.");
+ RWDEBUG("WiMAX-IP-Technology not found in reply");
RWDEBUG("Not calculating MN-HA keys");
}
*/
vp = pairfind(request->reply->vps, 10, VENDORPEC_WIMAX, TAG_ANY);
if (!vp) {
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
10, VENDORPEC_WIMAX);
}
if (!vp) {
*/
vp = pairfind(request->reply->vps, 11, VENDORPEC_WIMAX, TAG_ANY);
if (!vp) {
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
11, VENDORPEC_WIMAX);
}
if (!vp) {
*/
vp = pairfind(request->reply->vps, 10, VENDORPEC_WIMAX, TAG_ANY);
if (!vp) {
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
10, VENDORPEC_WIMAX);
}
if (!vp) {
*/
vp = pairfind(request->reply->vps, 11, VENDORPEC_WIMAX, TAG_ANY);
if (!vp) {
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
11, VENDORPEC_WIMAX);
}
if (!vp) {
*/
vp = pairfind(request->reply->vps, 12, VENDORPEC_WIMAX, TAG_ANY);
if (!vp) {
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
12, VENDORPEC_WIMAX);
}
if (!vp) {
*/
vp = pairfind(request->reply->vps, 13, VENDORPEC_WIMAX, TAG_ANY);
if (!vp) {
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
13, VENDORPEC_WIMAX);
}
if (!vp) {
if (fa_rk) {
vp = pairfind(request->reply->vps, 61, VENDORPEC_WIMAX, TAG_ANY);
if (!vp) {
- vp = radius_paircreate(request, &request->reply->vps,
+ vp = radius_paircreate(request->reply, &request->reply->vps,
61, VENDORPEC_WIMAX);
}
if (!vp) {
*/
vp = pairfind(request->packet->vps, 20, VENDORPEC_WIMAX, TAG_ANY);
if (vp) {
- RDEBUG("Client requested MN-HA key: Should use SPI to look up key from storage.");
+ RDEBUG("Client requested MN-HA key: Should use SPI to look up key from storage");
if (!mn_nai) {
RWDEBUG("MN-NAI was not found!");
}
*/
vp = pairfind(request->packet->vps, 58, VENDORPEC_WIMAX, TAG_ANY);
if (vp && (vp->vp_integer == 1)) {
- RDEBUG("Client requested HA-RK: Should use IP to look it up from storage.");
+ RDEBUG("Client requested HA-RK: Should use IP to look it up from storage");
}
}
as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
+ # We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
# works around shells that cannot unset nonexistent variables.
# Preserve -v and -x to the replacement shell.
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
+ [$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
+ [PREFIX]
By default, \`make install' will install all the files in
\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-yubikey-include-dir=DIR
- Directory where the yubikey includes may be found
+ Directory where the yubikey includes may be found
--with-yubikey-lib-dir=DIR
- Directory where the yubikey libraries may be found
+ Directory where the yubikey libraries may be found
--with-yubikey-dir=DIR Base directory where yubikey is installed
--with-ykclient-include-dir=DIR
- Directory where the ykclient includes may be found
+ Directory where the ykclient includes may be found
--with-ykclient-lib-dir=DIR
- Directory where the ykclient libraries may be found
+ Directory where the ykclient libraries may be found
--with-ykclient-dir=DIR Base directory where ykclient is installed
Some influential environment variables:
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
+ nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
- you have headers in a nonstandard directory <include dir>
+ you have headers in a nonstandard directory <include dir>
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
if test x$with_rlm_yubikey != xno; then
- yubikey_include_dir=
+ yubikey_include_dir=
# Check whether --with-yubikey-include-dir was given.
if test "${with_yubikey_include_dir+set}" = set; then :
fi
- yubikey_lib_dir=
+ yubikey_lib_dir=
# Check whether --with-yubikey-lib-dir was given.
if test "${with_yubikey_lib_dir+set}" = set; then :
- ykclient_include_dir=
+ ykclient_include_dir=
# Check whether --with-ykclient-include-dir was given.
if test "${with_ykclient_include_dir+set}" = set; then :
fi
- ykclient_lib_dir=
+ ykclient_lib_dir=
# Check whether --with-ykclient-lib-dir was given.
if test "${with_ykclient_lib_dir+set}" = set; then :
fi
if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
+ if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
+ 10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=yubikey.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
fi
if test "x$ac_cv_header_yubikey_h" != "xyes"; then
- have_ykclient="no"
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: yubikey headers not found. Use --with-yubikey-include-dir=<path>." >&5
+ have_ykclient="no"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: yubikey headers not found. Use --with-yubikey-include-dir=<path>." >&5
$as_echo "$as_me: WARNING: yubikey headers not found. Use --with-yubikey-include-dir=<path>." >&2;}
fi
- smart_try_dir="$yubikey_lib_dir"
+ smart_try_dir="$yubikey_lib_dir"
sm_lib_safe=`echo "yubikey" | sed 'y%./+-%__p_%'`
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lyubikey"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lyubikey"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libyubikey${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libyubikey.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
fi
if test "x$ac_cv_lib_yubikey_yubikey_aes_decrypt" != "xyes"; then
- have_yubikey="no"
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: yubikey libraries not found. Use --with-yubikey-lib-dir=<path>." >&5
+ have_yubikey="no"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: yubikey libraries not found. Use --with-yubikey-lib-dir=<path>." >&5
$as_echo "$as_me: WARNING: yubikey libraries not found. Use --with-yubikey-lib-dir=<path>." >&2;}
fi
$as_echo "#define HAVE_YUBIKEY 1" >>confdefs.h
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently building without yubikey token decryption support. requires: yubikey" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently building without yubikey token decryption support. requires: yubikey" >&5
$as_echo "$as_me: WARNING: silently building without yubikey token decryption support. requires: yubikey" >&2;}
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=ykclient.h
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_include_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
fi
if test "x$ac_cv_header_ykclient_h" != "xyes"; then
- have_ykclient="no"
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ykclient headers not found. Use --with-ykclient-include-dir=<path>." >&5
+ have_ykclient="no"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ykclient headers not found. Use --with-ykclient-include-dir=<path>." >&5
$as_echo "$as_me: WARNING: ykclient headers not found. Use --with-ykclient-include-dir=<path>." >&2;}
fi
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lykclient"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lykclient"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libykclient${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libykclient.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
fi
if test "x$ac_cv_lib_ykclient_ykclient_request_process" != "xyes"; then
- have_ykclient="no"
+ have_ykclient="no"
sm_lib_safe=`echo "ykclient" | sed 'y%./+-%__p_%'`
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- smart_lib="-lykclient"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ smart_lib="-lykclient"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libykclient${libltdl_cv_shlibext}
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
if test "x$LOCATE" != "x"; then
- DIRS=
+ DIRS=
file=libykclient.a
for x in `${LOCATE} $file 2>/dev/null`; do
- base=`echo $x | sed "s%/${file}%%"`
+ 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`
+ exclude=`echo ${dir} | ${GREP} /home`
if test "x$exclude" != "x"; then
continue
fi
- already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
+ already=`echo \$smart_lib_dir ${DIRS} | ${GREP} ${dir}`
if test "x$already" = "x"; then
DIRS="$DIRS $dir"
fi
SMART_LIBS="$smart_lib $SMART_LIBS"
fi
- if test "x$ac_cv_lib_ykclient_ykclient_request" == "xyes"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libykclient missing ykclient_request_process. A later version of libykclient is required." >&5
+ if test "x$ac_cv_lib_ykclient_ykclient_request" == "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libykclient missing ykclient_request_process. A later version of libykclient is required." >&5
$as_echo "$as_me: WARNING: libykclient missing ykclient_request_process. A later version of libykclient is required." >&2;}
- else
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ykclient libraries not found. Use --with-ykclient-lib-dir=<path>." >&5
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ykclient libraries not found. Use --with-ykclient-lib-dir=<path>." >&5
$as_echo "$as_me: WARNING: ykclient libraries not found. Use --with-ykclient-lib-dir=<path>." >&2;}
- fi
+ fi
fi
if test "x$have_ykclient" = "xyes"; then
if test x"$fail" != x""; then
if test x"${enable_strict_dependencies}" = x"yes"; then
- as_fn_error $? "set --without-rlm_yubikey to disable it explicitly." "$LINENO" 5
+ as_fn_error $? "set --without-rlm_yubikey to disable it explicitly." "$LINENO" 5
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_yubikey." >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_yubikey." >&5
$as_echo "$as_me: WARNING: silently not building rlm_yubikey." >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_yubikey requires: $fail." >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_yubikey requires: $fail." >&5
$as_echo "$as_me: WARNING: FAILURE: rlm_yubikey requires: $fail." >&2;};
- targetname=""
+ targetname=""
fi
fi
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
- case $cache_file in #(
- */* | ?:*)
+ case $cache_file in #(
+ */* | ?:*)
mv -f confcache "$cache_file"$$ &&
mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
+ *)
mv -f confcache "$cache_file" ;;
esac
fi
-V, --version print version number and configuration settings, then exit
--config print configuration, then exit
-q, --quiet, --silent
- do not print progress messages
+ do not print progress messages
-d, --debug don't remove temporary files
--recheck update $as_me by reconfiguring in the same conditions
--file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
+ instantiate the configuration file FILE
--header=FILE[:TEMPLATE]
- instantiate the configuration header FILE
+ instantiate the configuration header FILE
Configuration files:
$config_files
smart_try_dir="$yubikey_include_dir"
FR_SMART_CHECK_INCLUDE(yubikey.h)
if test "x$ac_cv_header_yubikey_h" != "xyes"; then
- have_ykclient="no"
- AC_MSG_WARN([yubikey headers not found. Use --with-yubikey-include-dir=<path>.])
+ have_ykclient="no"
+ AC_MSG_WARN([yubikey headers not found. Use --with-yubikey-include-dir=<path>.])
fi
dnl ############################################################
smart_try_dir="$yubikey_lib_dir"
FR_SMART_CHECK_LIB(yubikey, yubikey_aes_decrypt)
if test "x$ac_cv_lib_yubikey_yubikey_aes_decrypt" != "xyes"; then
- have_yubikey="no"
- AC_MSG_WARN([yubikey libraries not found. Use --with-yubikey-lib-dir=<path>.])
+ have_yubikey="no"
+ AC_MSG_WARN([yubikey libraries not found. Use --with-yubikey-lib-dir=<path>.])
fi
if test "x$have_yubikey" = "xyes"; then
- AC_DEFINE([HAVE_YUBIKEY],[1],[Build with yubikey token decryption support support from yubikey])
+ AC_DEFINE([HAVE_YUBIKEY],[1],[Build with yubikey token decryption support support from yubikey])
else
- AC_MSG_WARN([silently building without yubikey token decryption support. requires: yubikey])
+ AC_MSG_WARN([silently building without yubikey token decryption support. requires: yubikey])
fi
dnl ############################################################
smart_try_dir="$ykclient_include_dir"
FR_SMART_CHECK_INCLUDE([ykclient.h])
if test "x$ac_cv_header_ykclient_h" != "xyes"; then
- have_ykclient="no"
- AC_MSG_WARN([ykclient headers not found. Use --with-ykclient-include-dir=<path>.])
+ have_ykclient="no"
+ AC_MSG_WARN([ykclient headers not found. Use --with-ykclient-include-dir=<path>.])
fi
dnl ############################################################
smart_try_dir="$ykclient_lib_dir"
FR_SMART_CHECK_LIB([ykclient], [ykclient_request_process])
if test "x$ac_cv_lib_ykclient_ykclient_request_process" != "xyes"; then
- have_ykclient="no"
- FR_SMART_CHECK_LIB([ykclient], [ykclient_request])
- if test "x$ac_cv_lib_ykclient_ykclient_request" == "xyes"; then
- AC_MSG_WARN([libykclient missing ykclient_request_process. A later version of libykclient is required.])
- else
- AC_MSG_WARN([ykclient libraries not found. Use --with-ykclient-lib-dir=<path>.])
- fi
+ have_ykclient="no"
+ FR_SMART_CHECK_LIB([ykclient], [ykclient_request])
+ if test "x$ac_cv_lib_ykclient_ykclient_request" == "xyes"; then
+ AC_MSG_WARN([libykclient missing ykclient_request_process. A later version of libykclient is required.])
+ else
+ AC_MSG_WARN([ykclient libraries not found. Use --with-ykclient-lib-dir=<path>.])
+ fi
fi
if test "x$have_ykclient" = "xyes"; then
- AC_DEFINE([HAVE_YKCLIENT],[1],[Build with yubicloud support from ykclient])
+ AC_DEFINE([HAVE_YKCLIENT],[1],[Build with yubicloud support from ykclient])
else
AC_MSG_WARN([silently building without yubicloud support. requires: ykclient])
fi
dnl Don't change this section.
if test x"$fail" != x""; then
if test x"${enable_strict_dependencies}" = x"yes"; then
- AC_MSG_ERROR([set --without-]modname[ to disable it explicitly.])
+ AC_MSG_ERROR([set --without-]modname[ to disable it explicitly.])
else
- AC_MSG_WARN([silently not building ]modname[.])
- AC_MSG_WARN([FAILURE: ]modname[ requires: $fail.]);
- targetname=""
+ AC_MSG_WARN([silently not building ]modname[.])
+ AC_MSG_WARN([FAILURE: ]modname[ requires: $fail.]);
+ targetname=""
fi
fi
/** Decrypt a Yubikey OTP AES block
*
* @param inst Module configuration.
- * @param otp string to decrypt.
+ * @param passcode string to decrypt.
* @return one of the RLM_RCODE_* constants.
*/
-rlm_rcode_t rlm_yubikey_decrypt(rlm_yubikey_t *inst, REQUEST *request, VALUE_PAIR *otp)
+rlm_rcode_t rlm_yubikey_decrypt(rlm_yubikey_t *inst, REQUEST *request, char const *passcode)
{
uint32_t counter;
yubikey_token_st token;
return RLM_MODULE_INVALID;
}
- yubikey_parse(otp->vp_octets + inst->id_len, key->vp_octets, &token);
+ yubikey_parse((uint8_t const *) passcode + inst->id_len, key->vp_octets, &token);
/*
* Apparently this just uses byte offsets...
RDEBUG("Token data decrypted successfully");
- if (request->options && request->radlog) {
+ if (request->log.lvl && request->log.func) {
(void) fr_bin2hex((char *) &private_id, (uint8_t*) &token.uid, YUBIKEY_UID_SIZE);
RDEBUG2("Private ID : 0x%s", private_id);
RDEBUG2("Session counter : %u", yubikey_counter(token.ctr));
#ifdef HAVE_YKCLIENT
static const CONF_PARSER validation_config[] = {
- { "client_id", PW_TYPE_INTEGER, offsetof(rlm_yubikey_t, client_id), NULL, 0},
- { "api_key", PW_TYPE_STRING_PTR, offsetof(rlm_yubikey_t, api_key), NULL, NULL},
+ { "client_id", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_yubikey_t, client_id), 0 },
+ { "api_key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, rlm_yubikey_t, api_key), NULL },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
#endif
static const CONF_PARSER module_config[] = {
- { "id_length", PW_TYPE_INTEGER, offsetof(rlm_yubikey_t, id_len), NULL, "12" },
- { "decrypt", PW_TYPE_BOOLEAN, offsetof(rlm_yubikey_t, decrypt), NULL, "no" },
- { "validate", PW_TYPE_BOOLEAN, offsetof(rlm_yubikey_t, validate), NULL, "no" },
+ { "id_length", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_yubikey_t, id_len), "12" },
+ { "split", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_yubikey_t, split), "yes" },
+ { "decrypt", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_yubikey_t, decrypt), "no" },
+ { "validate", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_yubikey_t, validate), "no" },
#ifdef HAVE_YKCLIENT
- { "validation", PW_TYPE_SUBSECTION, 0, NULL, (void const *) validation_config },
+ { "validation", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) validation_config },
#endif
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
#ifndef HAVE_YUBIKEY
if (inst->decrypt) {
- EDEBUG("rlm_yubikey (%s): Requires libyubikey for OTP decryption", inst->name);
+ ERROR("rlm_yubikey (%s): Requires libyubikey for OTP decryption", inst->name);
return -1;
}
#endif
cs = cf_section_sub_find(conf, "validation");
if (!cs) {
- EDEBUG("rlm_yubikey (%s): Missing validation section", inst->name);
+ ERROR("rlm_yubikey (%s): Missing validation section", inst->name);
return -1;
}
return -1;
}
#else
- EDEBUG("rlm_yubikey (%s): Requires libykclient for OTP validation against Yubicloud servers", inst->name);
+ ERROR("rlm_yubikey (%s): Requires libykclient for OTP validation against Yubicloud servers", inst->name);
return -1;
#endif
}
}
#endif
+static int CC_HINT(nonnull) otp_string_valid(rlm_yubikey_t *inst, char const *otp, size_t len)
+{
+ size_t i;
+
+ for (i = inst->id_len; i < len; i++) {
+ if (!is_modhex(otp[i])) return -i;
+ }
+
+ return 1;
+}
+
+
/*
* Find the named user in this modules database. Create the set
* of attribute-value pairs to check and reply with for this user
* from the database. The authentication code only needs to check
* the password, the rest is done here.
*/
-static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
{
rlm_yubikey_t *inst = instance;
DICT_VALUE *dval;
char const *passcode;
- size_t i, len;
+ size_t len;
VALUE_PAIR *vp;
/*
* Don't print out debugging messages if we know
* they're useless.
*/
- if (request->packet->code == PW_ACCESS_CHALLENGE) {
+ if (request->packet->code == PW_CODE_ACCESS_CHALLENGE) {
return RLM_MODULE_NOOP;
}
- RDEBUG2("No Clear-Text password in the request. Can't do Yubikey authentication.");
+ RDEBUG2("No cleartext password in the request. Can't do Yubikey authentication");
return RLM_MODULE_NOOP;
}
passcode = request->password->vp_strvalue;
len = request->password->length;
+
/*
* Now see if the passcode is the correct length (in its raw
* modhex encoded form).
* <public_id (6-16 bytes)> + <aes-block (32 bytes)>
*
*/
- if (len != (inst->id_len + 32)) {
- RDEBUG2("User-Password value is not the correct length, expected %u, got %zu", inst->id_len + 32, len);
+ if (len > (inst->id_len + YUBIKEY_TOKEN_LEN)) {
+ /* May be a concatenation, check the last 32 bytes are modhex */
+ if (inst->split) {
+ char const *otp;
+ char *password;
+ size_t password_len;
+ int ret;
+
+ password_len = (len - (inst->id_len + YUBIKEY_TOKEN_LEN));
+ otp = passcode + password_len;
+ ret = otp_string_valid(inst, otp, (inst->id_len + YUBIKEY_TOKEN_LEN));
+ if (ret <= 0) {
+ if (RDEBUG_ENABLED3) {
+ RDMARKER(otp, -ret, "User-Password (aes-block) value contains non modhex chars");
+ } else {
+ RDEBUG("User-Password (aes-block) value contains non modhex chars");
+ }
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * Insert a new request attribute just containing the OTP
+ * portion.
+ */
+ vp = pairmake_packet("Yubikey-OTP", otp, T_OP_SET);
+ if (!vp) {
+ REDEBUG("Failed creating 'Yubikey-OTP' attribute");
+ return RLM_MODULE_FAIL;
+ }
+
+ /*
+ * Replace the existing string buffer for the password
+ * attribute with one just containing the password portion.
+ */
+ MEM(password = talloc_array(request->password, char, password_len + 1));
+ strlcpy(password, passcode, password_len + 1);
+ pairstrsteal(request->password, password);
+
+ RDEBUG3("request:Yubikey-OTP := '%s'", vp->vp_strvalue);
+ RDEBUG3("request:User-Password := '%s'", request->password->vp_strvalue);
+
+ /*
+ * So the ID split code works on the non password portion.
+ */
+ passcode = vp->vp_strvalue;
+ }
+ } else if (len < (inst->id_len + YUBIKEY_TOKEN_LEN)) {
+ RDEBUG2("User-Password value is not the correct length, expected at least %u bytes, got %zu bytes",
+ inst->id_len + YUBIKEY_TOKEN_LEN, len);
return RLM_MODULE_NOOP;
- }
-
- for (i = inst->id_len; i < len; i++) {
- if (!is_modhex(*passcode)) {
- RDEBUG2("User-Password (aes-block) value contains non modhex chars");
-
+ } else {
+ int ret;
+
+ ret = otp_string_valid(inst, passcode, (inst->id_len + YUBIKEY_TOKEN_LEN));
+ if (ret <= 0) {
+ if (RDEBUG_ENABLED3) {
+ RDMARKER(passcode, -ret, "User-Password (aes-block) value contains non modhex chars");
+ } else {
+ RDEBUG("User-Password (aes-block) value contains non modhex chars");
+ }
return RLM_MODULE_NOOP;
}
}
* needs to verify it's associated with the user.
*
* It's left up to the user if they want to decode it or not.
- *
- * @todo: is this even right? Is there anything in passcode other than
- * the public ID? Why pairmake(...NULL) instead of pairmake(..., passcode) ?
*/
if (inst->id_len) {
vp = pairmake(request, &request->packet->vps, "Yubikey-Public-ID", NULL, T_OP_SET);
return RLM_MODULE_FAIL;
}
- pairstrcpy(vp, passcode);
+ pairstrncpy(vp, passcode, inst->id_len);
}
return RLM_MODULE_OK;
}
+
/*
* Authenticate the user with the given password.
*/
-static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request)
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
{
rlm_rcode_t rcode = RLM_MODULE_NOOP;
rlm_yubikey_t *inst = instance;
- char const *passcode;
- size_t i, len;
+ char const *passcode = NULL;
+ DICT_ATTR const *da;
+ VALUE_PAIR const *vp;
+ size_t len;
+ int ret;
+
+ da = dict_attrbyname("Yubikey-OTP");
+ if (!da) {
+ RDEBUG2("No Yubikey-OTP attribute defined, falling back to User-Password");
+ goto user_password;
+ }
- /*
- * Can't do yubikey auth if there's no password.
- */
- if (!request->password || (request->password->da->attr != PW_USER_PASSWORD)) {
- REDEBUG("No Clear-Text password in the request. Can't do Yubikey authentication.");
- return RLM_MODULE_INVALID;
+ vp = pairfind_da(request->packet->vps, da, TAG_ANY);
+ if (vp) {
+ passcode = vp->vp_strvalue;
+ len = vp->length;
+ } else {
+ RDEBUG2("No Yubikey-OTP attribute found, falling back to User-Password");
+ user_password:
+ /*
+ * Can't do yubikey auth if there's no password.
+ */
+ if (!request->password || (request->password->da->attr != PW_USER_PASSWORD)) {
+ REDEBUG("No User-Password in the request. Can't do Yubikey authentication");
+ return RLM_MODULE_INVALID;
+ }
+
+ vp = request->password;
+ passcode = request->password->vp_strvalue;
+ len = request->password->length;
}
- passcode = request->password->vp_strvalue;
- len = request->password->length;
/*
* Verify the passcode is the correct length (in its raw
* modhex encoded form).
*
* <public_id (6-16 bytes)> + <aes-block (32 bytes)>
*/
- if (len != (inst->id_len + 32)) {
- REDEBUG("User-Password value is not the correct length, expected %u, got %zu", inst->id_len + 32, len);
+ if (len != (inst->id_len + YUBIKEY_TOKEN_LEN)) {
+ REDEBUG("%s value is not the correct length, expected bytes %u, got bytes %zu",
+ vp->da->name, inst->id_len + YUBIKEY_TOKEN_LEN, len);
return RLM_MODULE_INVALID;
}
- for (i = inst->id_len; i < len; i++) {
- if (!is_modhex(*passcode)) {
- RDEBUG2("User-Password (aes-block) value contains non modhex chars");
- return RLM_MODULE_INVALID;
+ ret = otp_string_valid(inst, passcode, (inst->id_len + YUBIKEY_TOKEN_LEN));
+ if (ret <= 0) {
+ if (RDEBUG_ENABLED3) {
+ REMARKER(passcode, -ret, "Passcode (aes-block) value contains non modhex chars");
+ } else {
+ RERROR("Passcode (aes-block) value contains non modhex chars");
}
+ return RLM_MODULE_INVALID;
}
#ifdef HAVE_YUBIKEY
if (inst->decrypt) {
- rcode = rlm_yubikey_decrypt(inst, request, request->password);
+ rcode = rlm_yubikey_decrypt(inst, request, passcode);
if (rcode != RLM_MODULE_OK) {
return rcode;
}
#ifdef HAVE_YKCLIENT
if (inst->validate) {
- return rlm_yubikey_validate(inst, request, request->password);
+ return rlm_yubikey_validate(inst, request, passcode);
}
#endif
return rcode;
#include <yubikey.h>
#endif
+#define YUBIKEY_TOKEN_LEN 32
+
/*
* Define a structure for our module configuration.
*
char const *name; //!< Instance name.
int auth_type; //!< Our Auth-Type.
unsigned int id_len; //!< The length of the Public ID portion of the OTP string.
+ bool split; //!< Split password string into components.
bool decrypt; //!< Decrypt the OTP string using the yubikey library.
bool validate; //!< Validate the OTP string using the ykclient library.
char const **uris; //!< Yubicloud URLs to validate the token against.
#ifdef HAVE_YKCLIENT
unsigned int client_id; //!< Validation API client ID.
- char *api_key; //!< Validation API signing key.
+ char const *api_key; //!< Validation API signing key.
ykclient_t *ykc; //!< ykclient configuration.
fr_connection_pool_t *conn_pool; //!< Connection pool instance.
#endif
/*
* decrypt.c - Decryption functions
*/
-rlm_rcode_t rlm_yubikey_decrypt(rlm_yubikey_t *inst, REQUEST *request, VALUE_PAIR *otp);
+rlm_rcode_t rlm_yubikey_decrypt(rlm_yubikey_t *inst, REQUEST *request, char const *passcode);
/*
* validate.c - Connection pool and validation functions
int rlm_yubikey_ykclient_detach(rlm_yubikey_t *inst);
-rlm_rcode_t rlm_yubikey_validate(rlm_yubikey_t *inst, REQUEST *request, VALUE_PAIR *otp);
+rlm_rcode_t rlm_yubikey_validate(rlm_yubikey_t *inst, REQUEST *request, char const *passcode);
status = ykclient_handle_init(inst->ykc, &yandle);
if (status != YKCLIENT_OK) {
- EDEBUG("rlm_yubikey (%s): %s", inst->name, ykclient_strerror(status));
+ ERROR("rlm_yubikey (%s): %s", inst->name, ykclient_strerror(status));
return NULL;
}
int count = 0;
if (!inst->client_id) {
- EDEBUG("rlm_yubikey (%s): client_id must be set when validation is enabled", inst->name);
+ ERROR("rlm_yubikey (%s): validation.client_id must be set (to a valid id) when validation is enabled",
+ inst->name);
return -1;
}
- if (!inst->api_key) {
- EDEBUG("rlm_yubikey (%s): api_key must be set when validation is enabled", inst->name);
+ if (!inst->api_key || !*inst->api_key || is_zero(inst->api_key)) {
+ ERROR("rlm_yubikey (%s): validation.api_key must be set (to a valid key) when validation is enabled",
+ inst->name);
return -1;
}
status = ykclient_global_init();
if (status != YKCLIENT_OK) {
yk_error:
- EDEBUG("rlm_yubikey (%s): %s", ykclient_strerror(status), inst->name);
+ ERROR("rlm_yubikey (%s): %s", ykclient_strerror(status), inst->name);
return -1;
}
init:
status = ykclient_set_client_b64(inst->ykc, inst->client_id, inst->api_key);
if (status != YKCLIENT_OK) {
- EDEBUG("rlm_yubikey (%s): Failed setting API credentials: %s", ykclient_strerror(status), inst->name);
+ ERROR("rlm_yubikey (%s): Failed setting API credentials: %s", ykclient_strerror(status), inst->name);
return -1;
}
return 0;
}
-rlm_rcode_t rlm_yubikey_validate(rlm_yubikey_t *inst, REQUEST *request, VALUE_PAIR *otp)
+rlm_rcode_t rlm_yubikey_validate(rlm_yubikey_t *inst, REQUEST *request, char const *passcode)
{
rlm_rcode_t rcode = RLM_MODULE_OK;
ykclient_rc status;
ykclient_handle_t *yandle;
yandle = fr_connection_get(inst->conn_pool);
- if (!yandle) {
- return RLM_MODULE_FAIL;
- }
+ if (!yandle) return RLM_MODULE_FAIL;
/*
* The libcurl multi-handle interface will tear down the TCP sockets for any partially completed
*/
ykclient_handle_cleanup(yandle);
- status = ykclient_request_process(inst->ykc, yandle, otp->vp_strvalue);
+ status = ykclient_request_process(inst->ykc, yandle, passcode);
if (status != YKCLIENT_OK) {
REDEBUG("%s", ykclient_strerror(status));
-
switch (status) {
- case YKCLIENT_BAD_OTP:
- case YKCLIENT_REPLAYED_OTP:
- rcode = RLM_MODULE_REJECT;
- break;
+ case YKCLIENT_BAD_OTP:
+ case YKCLIENT_REPLAYED_OTP:
+ rcode = RLM_MODULE_REJECT;
+ break;
- case YKCLIENT_NO_SUCH_CLIENT:
- rcode = RLM_MODULE_NOTFOUND;
- break;
+ case YKCLIENT_NO_SUCH_CLIENT:
+ rcode = RLM_MODULE_NOTFOUND;
+ break;
- default:
- rcode = RLM_MODULE_FAIL;
+ default:
+ rcode = RLM_MODULE_FAIL;
}
}
rlm_python
rlm_radutmp
rlm_realm
+rlm_rest
rlm_replicate
rlm_soh
rlm_sql
.cache
.foo
.bar
+.request
dictionary
test.conf
radius.log
RADDB_PATH := $(top_builddir)/raddb
TESTS = mschapv1 digest-01/digest* \
- test.example.com
+ test.example.com
PORT = 12340
#PORT = 1812
all: parse tests
clean:
- @rm -f $(RADDB_PATH)/test.conf test.conf dictionary
+ @rm -f test.conf dictionary
dictionary:
@echo "# test dictionary not install. Delete at any time." > dictionary
@echo '$$INCLUDE ' $(top_builddir)/share/dictionary >> dictionary
@echo '$$INCLUDE ' $(top_builddir)/src/tests/dictionary.test >> dictionary
@echo '$$INCLUDE ' $(top_builddir)/share/dictionary.dhcp >> dictionary
+ @echo '$$INCLUDE ' $(top_builddir)/share/dictionary.vqp >> dictionary
test.conf: dictionary
@echo "# test configuration file. Do not install. Delete at any time." > test.conf
@echo "libdir =" $(LIB_PATH) >> test.conf
@echo "testdir =" $(TEST_PATH) >> test.conf
@echo 'logdir = $${testdir}' >> test.conf
+ @echo 'maindir = ${top_builddir}/raddb/' >> test.conf
@echo 'radacctdir = $${testdir}' >> test.conf
@echo 'pidfile = $${testdir}/radiusd.pid' >> test.conf
- @echo '$$INCLUDE radiusd.conf' >> test.conf
+ @echo 'panic_action = "gdb -batch -x ${testdir}/panic.gdb %e %p > ${testdir}/gdb.log 2>&1; cat ${testdir}/gdb.log"' >> test.conf
+ @echo 'security {' >> $@
+ @echo ' allow_vulnerable_openssl = yes' >> $@
+ @echo '}' >> $@
+ @echo >> $@
+ @echo 'modconfdir = $${maindir}mods-config' >> $@
+ @echo 'certdir = $${maindir}/certs' >> $@
+ @echo 'cadir = $${maindir}/certs' >> $@
+ @echo '$$INCLUDE $${maindir}/radiusd.conf' >> test.conf
@echo '$$INCLUDE $${testdir}/config/' >> test.conf
-radiusd.pid: $(RADDB_PATH)/test.conf test.conf
+radiusd.pid: test.conf
@rm -f $(TEST_PATH)/gdb.log $(TEST_PATH)/radius.log
- @gdb -silent -x $(TEST_PATH)/gdb.conf --args \
- $(BIN_PATH)/radiusd -fPtxxxxml $(TEST_PATH)/radius.log -d $(RADDB_PATH) -n test -i 127.0.0.1 -p $(PORT) -D $(TEST_PATH) > $(TEST_PATH)/gdb.log 2>&1 &
+ @printf "Starting server... "
+ @if ! $(BIN_PATH)/radiusd -Pxxxxml $(TEST_PATH)/radius.log -d ${top_builddir}/src/tests -n test -i 127.0.0.1 -p $(PORT) -D $(TEST_PATH); then\
+ echo "failed"; \
+ echo "Last log entries were:"; \
+ tail -n 20 "$(TEST_PATH)/radius.log"; \
+ fi
+ @echo "ok"
# We can't make this depend on radiusd.pid, because then make will create
# radiusd.pid when we make radiusd.kill, which we don't want.
ret=0; \
if ! ps `cat $(TEST_PATH)/radiusd.pid` >/dev/null 2>&1; then \
rm -f radiusd.pid; \
- echo "FreeRADIUS terminated during test"; \
- echo "GDB output was:"; \
- cat "$(TEST_PATH)/gdb.log"; \
- echo "Last log entries were:"; \
- tail -n 20 $(TEST_PATH)/radius.log; \
- ret=1; \
+ echo "FreeRADIUS terminated during test"; \
+ echo "GDB output was:"; \
+ cat "$(TEST_PATH)/gdb.log"; \
+ echo "Last log entries were:"; \
+ tail -n 20 $(TEST_PATH)/radius.log; \
+ ret=1; \
fi; \
if ! kill -TERM `cat $(TEST_PATH)/radiusd.pid` >/dev/null 2>&1; then \
ret=1; \
fi
@rm -f radiusd.pid
-# Link from the main database directory to here
-$(RADDB_PATH)/test.conf: test.conf
- @[ -f $(RADDB_PATH)/test.conf ] || ln -s ../src/tests/test.conf $(RADDB_PATH)/
-
# kill the server (if it's running)
# start the server
# run the tests (ignoring any failures)
# kill the server
# remove the changes to raddb/
-tests: $(RADDB_PATH)/test.conf radiusd.kill
+tests: test.conf | radiusd.kill radiusd.pid
@chmod a+x runtests.sh
- @$(MAKE) radiusd.pid
- @echo "Waiting for server to start..."; \
- for i in 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0; do \
- printf "$$i "; \
- if [ -f '$(TEST_PATH)/radiusd.pid' ]; then \
- if ps `cat $(TEST_PATH)/radiusd.pid > /dev/null` > /dev/null 2>&1; then \
- echo; echo "Server started with PID" `cat $(TEST_PATH)/radiusd.pid`; \
- exit 0; \
- else \
- break; \
- fi; \
- fi; \
- sleep 1; \
- done; echo; \
- echo "FreeRADIUS daemon failed to start"; \
- echo "Last log entries were:"; \
- tail -n 20 "$(TEST_PATH)/radius.log"; \
- echo "GDB output was:"; \
- cat "$(TEST_PATH)/gdb.log"; \
- exit 1;
@BIN_PATH="$(BIN_PATH)" PORT="$(PORT)" ./runtests.sh $(TESTS)
@$(MAKE) radiusd.kill
- @rm -f $(RADDB_PATH)/test.conf
-tests.eap: $(RADDB_PATH)/test.conf radiusd.kill
+tests.eap: test.conf radiusd.kill
@chmod a+x runtests.sh
@rm -f $(TEST_PATH)/radius.log $(TEST_PATH)/gdb.log
@$(MAKE) radiusd.pid
@$(MAKE) eap
@$(MAKE) radiusd.kill
- @rm -f $(RADDB_PATH)/test.conf
eap: $(EAP_TLS_TESTS)
for x in $(EAP_TLS_TESTS); do \
done
md5:
- $(EAPOL_TEST) -c eap-md5.conf -s $(SECRET)
+ $(EAPOL_TEST) -c eap-md5.conf -s $(SECRET)
tls:
$(EAPOL_TEST) -c eap-ttls-tls.conf -s $(SECRET)
# The list is unordered. The order is added in the next step by looking
# at precursors.
#
-AUTH_FILES := $(filter-out %.conf %.md %.attrs %.mk %~,$(subst $(DIR)/,,$(wildcard $(DIR)/*)))
+AUTH_FILES := $(filter-out %.conf %.md %.attrs %.mk %~ %.rej,$(subst $(DIR)/,,$(wildcard $(DIR)/*)))
#
# Create the output directory
@rm -f $@
@for x in $^; do \
y=`grep 'PRE: ' $$x | sed 's/.*://;s/ / /g;s, , $(BUILD_DIR)/tests/auth/,g'`; \
- echo "$$x: $$y" >> $@; \
- echo "" >> $@; \
+ if [ "$$y" != "" ]; then \
+ z=`echo $$x | sed 's,src/,$(BUILD_DIR)/',`; \
+ echo "$$z: $$y" >> $@; \
+ echo "" >> $@; \
+ fi \
done
#
# These ones get copied over from the default input
#
$(BUILD_DIR)/tests/auth/%: $(DIR)/% $(BUILD_DIR)/tests/auth/%.attrs $(TESTBINDIR)/unittest | $(BUILD_DIR)/tests/auth $(AUTH_RADDB) $(AUTH_LIBS) build.raddb
@echo UNIT-TEST $(notdir $@)
- @if ! TESTDIR=$(notdir $@) $(TESTBIN)/unittest -D share -d src/tests/auth/ -i $@.attrs -f $@.attrs -xx > $@.log 2>&1; then \
+ @if ! TESTDIR=$(notdir $@) $(TESTBIN)/unittest -D share -d src/tests/auth/ -i $@.attrs -f $@.attrs -xxx > $@.log 2>&1; then \
if ! grep ERROR $< 2>&1 > /dev/null; then \
cat $@.log; \
echo "# $@.log"; \
--- /dev/null
+#
+# over-ride password set in radiusd.conf
+#
+update control {
+ Cleartext-Password -= 'hello'
+ Password-With-Header := 'oracle01'
+}
--- /dev/null
+User-Name = "bob"
+CHAP-Password = 'oracle01'
+
+Response-Packet-Type == Access-Accept
--- /dev/null
+#
+# over-ride password set in radiusd.conf
+#
+update control {
+ Cleartext-Password -= ANY
+ Password-With-Header := '{md5}5d41402abc4b2a76b9719d911017c592'
+}
--- /dev/null
+User-Name = "bob"
+User-Password = "hello"
+
+Response-Packet-Type == Access-Accept
--- /dev/null
+#
+# over-ride password set in radiusd.conf
+#
+update control {
+ Cleartext-Password -= 'hello'
+ Password-With-Header := '{clear}hello'
+}
--- /dev/null
+User-Name = "bob"
+User-Password = "hello"
+
+Response-Packet-Type == Access-Accept
--- /dev/null
+#
+# over-ride password set in radiusd.conf
+#
+update control {
+ Cleartext-Password -= 'hello'
+ Password-With-Header := 'hello'
+}
--- /dev/null
+User-Name = "bob"
+User-Password = "hello"
+
+Response-Packet-Type == Access-Accept
modconfdir = ${raddb}/mods-config
+# Only for testing!
+# Setting this on a production system is a BAD IDEA.
+security {
+ allow_vulnerable_openssl = yes
+}
+
modules {
$INCLUDE ${raddb}/mods-enabled/always
authenticate {
digest
- pap
+ pap
chap
}
}
test_port = 10000
+# Only for testing!
+# Setting this on a production system is a BAD IDEA.
+security {
+ allow_vulnerable_openssl = yes
+}
+
realm test.example.com {
authhost = 127.0.0.1:${test_port}
secret = testing123
load_factor = 10
}
- listen {
+ listen {
ipaddr = 127.0.0.1
port = ${test_port}
type = auth
# eapol_test -c eap-md5.conf -s testing123 -n
#
network={
- key_mgmt=NONE
- eap=MD5
- identity="bob"
- password="hello"
+ key_mgmt=NONE
+ eap=MD5
+ identity="bob"
+ password="hello"
}
# eapol_test -c eap-mschapv2.conf -s testing123
#
network={
- ssid="example"
- key_mgmt=WPA-EAP
- eap=MSCHAPV2
- identity="bob"
- password="bob"
+ ssid="example"
+ key_mgmt=WPA-EAP
+ eap=MSCHAPV2
+ identity="bob"
+ password="bob"
}
# eapol_test -c eap-ttls-mschapv2.conf -s testing123
#
network={
- ssid="example"
- key_mgmt=WPA-EAP
- eap=TTLS
- identity="bob"
- anonymous_identity="anonymous"
- password="bob"
- phase2="autheap=MSCHAPV2"
+ ssid="example"
+ key_mgmt=WPA-EAP
+ eap=TTLS
+ identity="bob"
+ anonymous_identity="anonymous"
+ password="bob"
+ phase2="autheap=MSCHAPV2"
}
# eapol_test -c eap-ttls-mschapv2.conf -s testing123
#
network={
- ssid="example"
- key_mgmt=WPA-EAP
- eap=TTLS
- identity="bob"
- anonymous_identity="anonymous"
- password="bob"
- phase2="auth=MSCHAPV2"
+ ssid="example"
+ key_mgmt=WPA-EAP
+ eap=TTLS
+ identity="bob"
+ anonymous_identity="anonymous"
+ password="bob"
+ phase2="auth=MSCHAPV2"
}
# eapol_test -c eap-ttls-pap.conf -s testing123
#
network={
- key_mgmt=WPA-EAP
- eap=TTLS
- identity="bob"
- anonymous_identity="anonymous"
- password="hello"
- phase2="auth=PAP"
+ key_mgmt=WPA-EAP
+ eap=TTLS
+ identity="bob"
+ anonymous_identity="anonymous"
+ password="hello"
+ phase2="auth=PAP"
}
SHA1buffer was: 65617073_696d0011_22334455_66771021_32435465_
- 76873041_52637485_96a74d6c_40de483a_dd995090_
- 2c4024ce_765e0002_00010001
+ 76873041_52637485_96a74d6c_40de483a_dd995090_
+ 2c4024ce_765e0002_00010001
Input was:
identity: (len=6)65617073696d
nonce_mt: 4d6c40de483add9950902c4024ce765e
K_aut: 54323970_481b5159_48d00a34_422bbe3c
K_encr: 72469fd8_bb6c2a4a_93ac42e5_b4668acb
msk: 0a572a3f_2baeea10_640598c9_41901995_f842097a
- cbb13272_bc949b66_8fb4f5a3_deefed09_3947fe64
- c88f7df8_dadcab5f_8d003913_8e9bcff7_1a810316
- 11eeb959
+ cbb13272_bc949b66_8fb4f5a3_deefed09_3947fe64
+ c88f7df8_dadcab5f_8d003913_8e9bcff7_1a810316
+ 11eeb959
emsk: 207256b3_9ada49ef_c1850c12_30461921_d700f9f7
- 83a0f5a9_cff155bd_6c8f1aa5_072b7530_af44f515
- 3cb983b0_8343effa_2eb161e2_7d3543bc_5bd6db22
- 993af27b
+ 83a0f5a9_cff155bd_6c8f1aa5_072b7530_af44f515
+ 3cb983b0_8343effa_2eb161e2_7d3543bc_5bd6db22
+ 993af27b
SHA1buffer was: 31323434_30373031_30303030_30303031_40656170_
- 73696d2e_666f6fa0_a1a2a3a4_a5a6a7b0_b1b2b3b4_
- b5b6b7c0_c1c2c3c4_c5c6c701_23456789_abcdeffe_
- dcba9876_54321000_010001
+ 73696d2e_666f6fa0_a1a2a3a4_a5a6a7b0_b1b2b3b4_
+ b5b6b7c0_c1c2c3c4_c5c6c701_23456789_abcdeffe_
+ dcba9876_54321000_010001
Input was:
identity: (len=27)313234343037303130303030303030314065617073696d2e666f6f
nonce_mt: 0123456789abcdeffedcba9876543210
K_aut: 25af1942_efcbf4bc_72b39434_21f2a974
K_encr: 536e5ebc_4465582a_a6a8ec99_86ebb620
msk: 39d45aea_f4e30601_983e972b_6cfd46d1_c3637733
- 65690d09_cd44976b_525f47d3_a60a985e_955c53b0
- 90b2e4b7_3719196a_40254296_8fd14a88_8f46b9a7
- 886e4488
+ 65690d09_cd44976b_525f47d3_a60a985e_955c53b0
+ 90b2e4b7_3719196a_40254296_8fd14a88_8f46b9a7
+ 886e4488
emsk: 5949eab0_fff69d52_315c6c63_4fd14a7f_0d52023d
- 56f79698_fa6596ab_eed4f93f_bb48eb53_4d985414
- ceed0d9a_8ed33c38_7c9dfdab_92ffbdf2_40fcecf6
- 5a2c93b9
+ 56f79698_fa6596ab_eed4f93f_bb48eb53_4d985414
+ ceed0d9a_8ed33c38_7c9dfdab_92ffbdf2_40fcecf6
+ 5a2c93b9
K_aut: 72cd7e8c_f2086e24_a98c1780_bc3d745b
K_encr: be789668_329769c3_73c0b64b_beffd665
msk: 9be9fbc9_5415fa9e_f9d52563_bddd9758_65a3fadb
- 47a5815a_7310cf3f_10123d4e_ccaf9d4b_30b13c80
- 4dd130e5_117f35ae_a0e50b43_9a08b80d_dd15922c
- f7fd9956
+ 47a5815a_7310cf3f_10123d4e_ccaf9d4b_30b13c80
+ 4dd130e5_117f35ae_a0e50b43_9a08b80d_dd15922c
+ f7fd9956
emsk: 5dd5a779_65415b21_69aa1300_09dc6ba4_96433d1e
- 72065983_cbe8bc1d_6d744c99_dc76f16f_24324709
- cb731af2_fbe69c6a_dd302662_a083d7e2_7c05c7cd
- 279c3f66
+ 72065983_cbe8bc1d_6d744c99_dc76f16f_24324709
+ cb731af2_fbe69c6a_dd302662_a083d7e2_7c05c7cd
+ 279c3f66
MAC check succeed
+++> About to send encoded packet:
K_aut: 72cd7e8c_f2086e24_a98c1780_bc3d745b
K_encr: be789668_329769c3_73c0b64b_beffd665
msk: 9be9fbc9_5415fa9e_f9d52563_bddd9758_65a3fadb
- 47a5815a_7310cf3f_10123d4e_ccaf9d4b_30b13c80
- 4dd130e5_117f35ae_a0e50b43_9a08b80d_dd15922c
- f7fd9956
+ 47a5815a_7310cf3f_10123d4e_ccaf9d4b_30b13c80
+ 4dd130e5_117f35ae_a0e50b43_9a08b80d_dd15922c
+ f7fd9956
emsk: 5dd5a779_65415b21_69aa1300_09dc6ba4_96433d1e
- 72065983_cbe8bc1d_6d744c99_dc76f16f_24324709
- cb731af2_fbe69c6a_dd302662_a083d7e2_7c05c7cd
- 279c3f66
+ 72065983_cbe8bc1d_6d744c99_dc76f16f_24324709
+ cb731af2_fbe69c6a_dd302662_a083d7e2_7c05c7cd
+ 279c3f66
MAC check succeed
+++> About to send encoded packet:
#
usercollide = no
-# lower_user / lower_pass:
+# lower_user / lower_pass:
# Lower case the username/password "before" or "after"
-# attempting to authenticate.
+# attempting to authenticate.
#
# If "before", the server will first modify the request and then try
# to auth the user. If "after", the server will first auth using the
# Normally this should be set to "no", because they're useless.
# See: http://www.freeradius.org/rfc/rfc2865.html#Keep-Alives
#
- # However, certain NAS boxes may require them.
+ # However, certain NAS boxes may require them.
#
# When sent a Status-Server message, the server responds with
# and Access-Accept packet, containing a Reply-Message attribute,
# 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
# Extensible Authentication Protocol
#
- # For all EAP related authentications
+ # For all EAP related authentications
eap {
# Invoke the default supported EAP type when
# EAP-Identity response is received.
md5 {
}
- sim {
- }
+ sim {
+ }
# Cisco LEAP
#
leap {
}
- ## EAP-TLS is highly experimental EAP-Type at the moment.
+ ## EAP-TLS is highly experimental EAP-Type at the moment.
# Please give feedback on the mailing list.
#tls {
# private_key_password = password
# to overwrite (or add) Auth-Type during
# authorization. Normally should be MS-CHAP
authtype = MS-CHAP
-
+
# if use_mppe is not set to no mschap will
# add MS-CHAP-MPPE-Keys for MS-CHAPv1 and
# MS-MPPE-Recv-Key/MS-MPPE-Send-Key for MS-CHAPv2
# This module definition allows you to use LDAP for
# authorization and authentication (Auth-Type := LDAP)
#
- # See doc/rlm_ldap for description of configuration options
- # and sample authorize{} and authenticate{} blocks
+ # See doc/rlm_ldap for description of configuration options
+ # and sample authorize{} and authenticate{} blocks
ldap {
server = "ldap.your.domain"
# identity = "cn=admin,o=My Org,c=UA"
# password = mypass
basedn = "o=My Org,c=UA"
- filter = "(uid=%{Stripped-User-Name:-%{User-Name}})"
+ filter = "(uid=%{%{Stripped-User-Name}:-%{User-Name}})"
# set this to 'yes' to use TLS encrypted connections
# to the LDAP database by using the StartTLS extended
# ignore_nislike - ignore NIS-related records
# delimiter - symbol to use as a field separator in passwd file,
# for format ':' symbol is always used. '\0', '\n' are
- # not allowed
+ # not allowed
#
# An example configuration for using /etc/smbpasswd.
format = suffix
delimiter = "%"
}
-
+
# Preprocess the incoming RADIUS request, before handing it off
# to other modules.
#
# If we want to believe the 'utmp' file, then this
# configuration entry can be set to 'no'.
#
- check_with_nas = yes
+ check_with_nas = yes
# Set the file permissions, as the contents of this file
# are usually private.
# If you wish to execute an external program in more than
# one section (e.g. 'authorize', 'pre_proxy', etc), then it
# is probably best to define a different instance of the
- # 'exec' module for every section.
- #
+ # 'exec' module for every section.
+ #
exec echo {
#
# Wait for the program to finish.
# The order of the realm modules will determine the order that
# we try to find a matching realm.
#
-# Make *sure* that 'preprocess' comes before any realm if you
+# Make *sure* that 'preprocess' comes before any realm if you
# need to setup hints for the remote radius server
authorize {
#
#
# It also adds a Client-IP-Address attribute to the request.
preprocess
-
+
#
# The chap module will set 'Auth-Type := CHAP' if we are
# handling a CHAP request and Auth-Type has not already been set
# module checks the users password. Note that packets
# containing CHAP-Password attributes CANNOT be authenticated
# against /etc/passwd! See the FAQ for details.
- #
+ #
unix
# Uncomment it if you want to use ldap for authentication
}
-# Session database, used for checking Simultaneous-Use. Either the radutmp
+# Session database, used for checking Simultaneous-Use. Either the radutmp
# or rlm_sql module can handle this.
# The rlm_sql module is *much* faster
session {
EAP-Sim-KC3 = 0xc0c1c2c3c4c5c6c7,
1232420100000015 Auth-Type := EAP, Autz-Type:=EAP, EAP-Type := SIM
- EAP-Sim-Rand1 = 0x30000000000000000000000000000000,
- EAP-Sim-SRES1 = 0x30112233,
- EAP-Sim-KC1 = 0x445566778899AABB,
- EAP-Sim-Rand2 = 0x31000000000000000000000000000000,
- EAP-Sim-SRES2 = 0x31112233,
- EAP-Sim-KC2 = 0x445566778899AABB,
- EAP-Sim-Rand3 = 0x32000000000000000000000000000000,
- EAP-Sim-SRES3 = 0x32112233,
- EAP-Sim-KC3 = 0x445566778899AABB,
+ EAP-Sim-Rand1 = 0x30000000000000000000000000000000,
+ EAP-Sim-SRES1 = 0x30112233,
+ EAP-Sim-KC1 = 0x445566778899AABB,
+ EAP-Sim-Rand2 = 0x31000000000000000000000000000000,
+ EAP-Sim-SRES2 = 0x31112233,
+ EAP-Sim-KC2 = 0x445566778899AABB,
+ EAP-Sim-Rand3 = 0x32000000000000000000000000000000,
+ EAP-Sim-SRES3 = 0x32112233,
+ EAP-Sim-KC3 = 0x445566778899AABB,
eapsim Auth-Type := EAP, Autz-Type:=EAP, EAP-Type := SIM
- EAP-Sim-Rand1 = 0xabcd1234abcd1234abcd1234abcd1234,
- EAP-Sim-SRES1 = 0x1234abcd,
- EAP-Sim-KC1 = 0x0011223344556677,
- EAP-Sim-Rand2 = 0xbcd1234abcd1234abcd1234abcd1234a,
- EAP-Sim-SRES2 = 0x234abcd1,
- EAP-Sim-KC2 = 0x1021324354657687,
- EAP-Sim-Rand3 = 0xcd1234abcd1234abcd1234abcd1234ab,
- EAP-Sim-SRES3 = 0x34abcd12,
- EAP-Sim-KC3 = 0x30415263748596a7
+ EAP-Sim-Rand1 = 0xabcd1234abcd1234abcd1234abcd1234,
+ EAP-Sim-SRES1 = 0x1234abcd,
+ EAP-Sim-KC1 = 0x0011223344556677,
+ EAP-Sim-Rand2 = 0xbcd1234abcd1234abcd1234abcd1234a,
+ EAP-Sim-SRES2 = 0x234abcd1,
+ EAP-Sim-KC2 = 0x1021324354657687,
+ EAP-Sim-Rand3 = 0xcd1234abcd1234abcd1234abcd1234ab,
+ EAP-Sim-SRES3 = 0x34abcd12,
+ EAP-Sim-KC3 = 0x30415263748596a7
K_aut: 2853a70a_4ca089cc_0cf8a24a_45ecec93
K_encr: 77987afb_1cfd251d_749d2f16_0611338e
msk: e8adff17_1d82d5e6_9a78d526_1e86ee56_93cbe646
- 59332585_1f1f58f0_598c3a0c_1640339b_c3407fb4
- 56a14ada_a4791445_e8a3cf40_49b4628f_8e9f597a
- 7891e9d2
+ 59332585_1f1f58f0_598c3a0c_1640339b_c3407fb4
+ 56a14ada_a4791445_e8a3cf40_49b4628f_8e9f597a
+ 7891e9d2
emsk: b33c4a19_c1df9108_17196271_7c4b7f98_e53a64ba
- a67d4e23_5ff142cb_6e427434_8a71358a_3c2b1313
- 4cec6be3_a99e60c8_ae543fdd_52ecd7b3_0542e1df
- 5d10c5f7
+ a67d4e23_5ff142cb_6e427434_8a71358a_3c2b1313
+ 4cec6be3_a99e60c8_ae543fdd_52ecd7b3_0542e1df
+ 5d10c5f7
MAC check succeed
+++> About to send encoded packet:
-
\ No newline at end of file
K_aut: a4c96a3c_1b4e1932_acc3878d_ecb5d9c6
K_encr: f544a796_43c4d95f_90aaa5b7_74267742
msk: 8000f5e4_ed05a9bf_17b9ec6a_27f92d9d_f104966b
- 03689665_de45db49_82ecdcc4_85c26910_e886de4f
- bdfa4218_b4ef2f64_319c9b41_b77b3c90_69d616f9
- 0781438a
+ 03689665_de45db49_82ecdcc4_85c26910_e886de4f
+ bdfa4218_b4ef2f64_319c9b41_b77b3c90_69d616f9
+ 0781438a
emsk: 3c87c92f_44193e35_dd18e906_3d7cff8f_cb6d6002
- bf233300_5df66776_70086929_f0d27970_3e59c480
- 675d6b45_0dc6a79a_51dc34b0_7091a5ff_8ca145ce
- 98accef2
+ bf233300_5df66776_70086929_f0d27970_3e59c480
+ 675d6b45_0dc6a79a_51dc34b0_7091a5ff_8ca145ce
+ 98accef2
hmac-sha1 key(16): a4c96a3c_1b4e1932_acc3878d_ecb5d9c6
DATA: (96) 01YY0050_120b0000_010d0000_30000000_00000000
- 00000000_00000000_31000000_00000000_00000000
- 00000000_32000000_00000000_00000000_00000000
- 0b050000_00000000_00000000_00000000_00000000
- 1b764ea5_668faa4b_0e7dd876_d25753f8
+ 00000000_00000000_31000000_00000000_00000000
+ 00000000_32000000_00000000_00000000_00000000
+ 0b050000_00000000_00000000_00000000_00000000
+ 1b764ea5_668faa4b_0e7dd876_d25753f8
hmac-sha1 mac(20): XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX
MAC check succeed
hmac-sha1 key(16): a4c96a3c_1b4e1932_acc3878d_ecb5d9c6
DATA: (40) 02YY001c_120b0000_0b050000_00000000_00000000
- 00000000_00000000_30112233_31112233_32112233
+ 00000000_00000000_30112233_31112233_32112233
hmac-sha1 mac(20): XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX
K_aut: a4c96a3c_1b4e1932_acc3878d_ecb5d9c6
K_encr: f544a796_43c4d95f_90aaa5b7_74267742
msk: 8000f5e4_ed05a9bf_17b9ec6a_27f92d9d_f104966b
- 03689665_de45db49_82ecdcc4_85c26910_e886de4f
- bdfa4218_b4ef2f64_319c9b41_b77b3c90_69d616f9
- 0781438a
+ 03689665_de45db49_82ecdcc4_85c26910_e886de4f
+ bdfa4218_b4ef2f64_319c9b41_b77b3c90_69d616f9
+ 0781438a
emsk: 3c87c92f_44193e35_dd18e906_3d7cff8f_cb6d6002
- bf233300_5df66776_70086929_f0d27970_3e59c480
- 675d6b45_0dc6a79a_51dc34b0_7091a5ff_8ca145ce
- 98accef2
+ bf233300_5df66776_70086929_f0d27970_3e59c480
+ 675d6b45_0dc6a79a_51dc34b0_7091a5ff_8ca145ce
+ 98accef2
hmac-sha1 key(16): a4c96a3c_1b4e1932_acc3878d_ecb5d9c6
DATA: (96) 01YY0050_120b0000_010d0000_30000000_00000000
- 00000000_00000000_31000000_00000000_00000000
- 00000000_32000000_00000000_00000000_00000000
- 0b050000_00000000_00000000_00000000_00000000
- 1b764ea5_668faa4b_0e7dd876_d25753f8
+ 00000000_00000000_31000000_00000000_00000000
+ 00000000_32000000_00000000_00000000_00000000
+ 0b050000_00000000_00000000_00000000_00000000
+ 1b764ea5_668faa4b_0e7dd876_d25753f8
hmac-sha1 mac(20): XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX
MAC check succeed
hmac-sha1 key(16): a4c96a3c_1b4e1932_acc3878d_ecb5d9c6
DATA: (40) 02YY001c_120b0000_0b050000_00000000_00000000
- 00000000_00000000_30112233_31112233_32112233
+ 00000000_00000000_30112233_31112233_32112233
hmac-sha1 mac(20): XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX
K_aut: a4c96a3c_1b4e1932_acc3878d_ecb5d9c6
K_encr: f544a796_43c4d95f_90aaa5b7_74267742
msk: 8000f5e4_ed05a9bf_17b9ec6a_27f92d9d_f104966b
- 03689665_de45db49_82ecdcc4_85c26910_e886de4f
- bdfa4218_b4ef2f64_319c9b41_b77b3c90_69d616f9
- 0781438a
+ 03689665_de45db49_82ecdcc4_85c26910_e886de4f
+ bdfa4218_b4ef2f64_319c9b41_b77b3c90_69d616f9
+ 0781438a
emsk: 3c87c92f_44193e35_dd18e906_3d7cff8f_cb6d6002
- bf233300_5df66776_70086929_f0d27970_3e59c480
- 675d6b45_0dc6a79a_51dc34b0_7091a5ff_8ca145ce
- 98accef2
+ bf233300_5df66776_70086929_f0d27970_3e59c480
+ 675d6b45_0dc6a79a_51dc34b0_7091a5ff_8ca145ce
+ 98accef2
hmac-sha1 key(16): a4c96a3c_1b4e1932_acc3878d_ecb5d9c6
DATA: (96) 01280050_120b0000_010d0000_30000000_00000000
- 00000000_00000000_31000000_00000000_00000000
- 00000000_32000000_00000000_00000000_00000000
- 0b050000_00000000_00000000_00000000_00000000
- 1b764ea5_668faa4b_0e7dd876_d25753f8
+ 00000000_00000000_31000000_00000000_00000000
+ 00000000_32000000_00000000_00000000_00000000
+ 0b050000_00000000_00000000_00000000_00000000
+ 1b764ea5_668faa4b_0e7dd876_d25753f8
hmac-sha1 mac(20): a91362ad_f370809a_c998c123_ebcb32bd_6a2915c2
MAC check succeed
hmac-sha1 key(16): a4c96a3c_1b4e1932_acc3878d_ecb5d9c6
DATA: (40) 0228001c_120b0000_0b050000_00000000_00000000
- 00000000_00000000_30112233_31112233_32112233
+ 00000000_00000000_30112233_31112233_32112233
hmac-sha1 mac(20): 7a3818ad_17959b80_99cd84eb_64e45346_d63098e9
Input was: |bd029bbe_7f51960b_cf9edb2b_61f06f0f_eb5a38b6|
Output was: 2070b322_3dba372f_de1c0ffc_7b2e3b49_8b260614
- 3c6c18ba_cb0f6c55_babb1378_8e20d737_a3275116
- c9ec5c2f_3261cba3_98384ecf_9189707c_20dbe3b6
- 8d6fc9d2_37313854_7338c3f5_7cf68f38_683aea5b
- f9e60c0d_73b177bc_69edde1b_eb3f596a_9555fee9
- 0d570204_a3044bb5_a67f6509_25f14c1d_0446b252
- 78360140_28faffbf_49840408_ccb30408_00b40408
- 38faffbf_18ef0440_48ae1340_c0970040_48faffbf
+ 3c6c18ba_cb0f6c55_babb1378_8e20d737_a3275116
+ c9ec5c2f_3261cba3_98384ecf_9189707c_20dbe3b6
+ 8d6fc9d2_37313854_7338c3f5_7cf68f38_683aea5b
+ f9e60c0d_73b177bc_69edde1b_eb3f596a_9555fee9
+ 0d570204_a3044bb5_a67f6509_25f14c1d_0446b252
+ 78360140_28faffbf_49840408_ccb30408_00b40408
+ 38faffbf_18ef0440_48ae1340_c0970040_48faffbf
--- /dev/null
+#
+# PRE: update
+#
+update request {
+ 3GPP-IMSI := "hello"
+}
+
+#
+# "request:[0-9]" should be parsed as a list followed
+# by an attribute.
+#
+update control {
+ Tmp-String-0 := "%{3GPP-IMSI}"
+ Tmp-String-1 := "%{request:3GPP-IMSI}"
+}
+
+update reply {
+ Filter-Id := "filter"
+}
\ No newline at end of file
# The list is unordered. The order is added in the next step by looking
# at precursors.
#
-FILES := $(filter-out %.conf %.md %.attrs %.mk %~,$(subst $(DIR)/,,$(wildcard $(DIR)/*)))
+KEYWORD_FILES := $(filter-out %.conf %.md %.attrs %.mk %~ %.rej,$(subst $(DIR)/,,$(wildcard $(DIR)/*)))
#
# Create the output directory
# strip out the ones which exist
# move the filenames to the build directory.
#
-BOOTSTRAP_EXISTS := $(addprefix $(DIR)/,$(addsuffix .attrs,$(FILES)))
+BOOTSTRAP_EXISTS := $(addprefix $(DIR)/,$(addsuffix .attrs,$(KEYWORD_FILES)))
BOOTSTRAP_NEEDS := $(filter-out $(wildcard $(BOOTSTRAP_EXISTS)),$(BOOTSTRAP_EXISTS))
BOOTSTRAP := $(subst $(DIR),$(BUILD_DIR)/tests/keywords,$(BOOTSTRAP_NEEDS))
#
-include $(BUILD_DIR)/tests/keywords/depends.mk
-$(BUILD_DIR)/tests/keywords/depends.mk: $(addprefix $(DIR)/,$(FILES)) | $(BUILD_DIR)/tests/keywords
+export OPENSSL_LIBS
+
+$(BUILD_DIR)/tests/keywords/depends.mk: $(addprefix $(DIR)/,$(KEYWORD_FILES)) | $(BUILD_DIR)/tests/keywords
@rm -f $@
@for x in $^; do \
y=`grep 'PRE: ' $$x | sed 's/.*://;s/ / /g;s, , $(BUILD_DIR)/tests/keywords/,g'`; \
- echo "$$x: $$y" >> $@; \
- echo "" >> $@; \
+ if [ "$$y" != "" ]; then \
+ z=`echo $$x | sed 's,src/,$(BUILD_DIR)/',`; \
+ echo "$$z: $$y" >> $@; \
+ echo "" >> $@; \
+ fi \
done
#
#
# Get all of the unit test output files
#
-TESTS.KEYWORDS_FILES := $(addprefix $(BUILD_DIR)/tests/keywords/,$(FILES))
+TESTS.KEYWORDS_FILES := $(addprefix $(BUILD_DIR)/tests/keywords/,$(KEYWORD_FILES))
#
# Depend on the output files, and create the directory first.
--- /dev/null
+#
+# PRE: if
+#
+# Tests for dereferencing the Nth attribute
+#
+update request {
+ Class := 0x01020304
+ Class += 0x05060708
+ Class += 0x090a0b0c
+}
+
+if (&Class != 0x01020304) {
+ update reply {
+ Filter-Id := "fail 0"
+ }
+}
+
+# Must be the same as above
+if (&Class[0] != 0x01020304) {
+ update reply {
+ Filter-Id += "fail 0a"
+ }
+}
+
+if (&Class[1] != 0x05060708) {
+ update reply {
+ Filter-Id += "fail 1"
+ }
+}
+
+if (&Class[2] != 0x090a0b0c) {
+ update reply {
+ Filter-Id += "fail 2"
+ }
+}
+
+# must not exist
+if (&Class[3]) {
+ update reply {
+ Filter-Id += "fail 3"
+ }
+}
+
+#
+# The test passes only if no test above
+# added a Filter-Id
+#
+if (!reply:Filter-Id) {
+ update reply {
+ Filter-Id := "filter"
+ }
+}
--- /dev/null
+#
+# PRE: hex
+#
+update reply {
+ Filter-Id := "filter"
+}
+
+update request {
+ Tmp-String-0 := '9870'
+ Tmp-Octets-0 := 0x39383731
+ Tmp-IP-Address-0 := 57.56.55.50
+ Tmp-Date-0 := 959985459
+ Tmp-Integer-0 := 959985460
+ Tmp-Cast-Abinary := 'ip out forward srcip 57.56.55.53/32 udp dstport = 1812'
+ Tmp-Cast-IfId := '0000:0000:3938:3737'
+ Tmp-Cast-IPv6Addr := '::3938:3738'
+ Tmp-Cast-IPv6Prefix := '::3938:3739/128'
+ Tmp-Cast-Byte := 58
+ Tmp-Cast-Short := 14139
+ Tmp-Cast-Ethernet := 00:00:39:38:37:3c
+ Tmp-Cast-Integer64 := 1152921505566832445
+ Tmp-Cast-IPv4Prefix := 57.56.55.62/32
+}
+
+update request {
+ Tmp-String-0 := "%{base64:&Tmp-String-0}"
+ Tmp-String-1 := "%{base64:&Tmp-Octets-0}"
+ Tmp-String-2 := "%{base64:&Tmp-IP-Address-0}"
+ Tmp-String-3 := "%{base64:&Tmp-Date-0}"
+ Tmp-String-4 := "%{base64:&Tmp-Integer-0}"
+ Tmp-String-5 := "%{base64:&Tmp-Cast-Abinary}"
+ Tmp-String-6 := "%{base64:&Tmp-Cast-Ifid}"
+ Tmp-String-7 := "%{base64:&Tmp-Cast-IPv6Addr}"
+ Tmp-String-8 := "%{base64:&Tmp-Cast-IPv6Prefix}"
+ Tmp-String-9 := "%{base64:&Tmp-Cast-Byte}"
+}
+
+# String - bin 0x39383730
+if (Tmp-String-0 != 'OTg3MA==') {
+ update reply {
+ Filter-Id += 'fail 0'
+ }
+}
+
+# Octets - bin 0x39383731
+if (Tmp-String-1 != 'OTg3MQ==') {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+# IP Address - bin 0x39383732
+if (Tmp-String-2 != 'OTg3Mg==') {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+# Date - bin 0x39383733
+if (Tmp-String-3 != 'OTg3Mw==') {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+# Integer - bin 0x39383734
+if (Tmp-String-4 != 'OTg3NA==') {
+ update reply {
+ Filter-Id += 'fail 4'
+ }
+}
+
+# Abinary - bin 0x0101000039383735000000002000110000000714000200000000000000000000
+if (Tmp-String-5 != 'AQEAADk4NzUAAAAAIAARAAAABxQAAgAAAAAAAAAAAAA=') {
+ update reply {
+ Filter-Id += 'fail 5'
+ }
+}
+
+# ifid - bin 0x0000000039383737
+if (Tmp-String-6 != 'AAAAADk4Nzc=') {
+ update reply {
+ Filter-Id += 'fail 6'
+ }
+}
+
+# ipv6addr - bin 0x00000000000000000000000039383738
+if (Tmp-String-7 != 'AAAAAAAAAAAAAAAAOTg3OA==') {
+ update reply {
+ Filter-ID += 'fail 7'
+ }
+}
+
+# ipv6addrprefix - bin 0x008000000000000000000000000039383739
+if (Tmp-String-8 != 'AIAAAAAAAAAAAAAAAAA5ODc5') {
+ update reply {
+ Filter-ID += 'fail 8'
+ }
+}
+
+# byte - bin 0x3a
+if (Tmp-String-9 != 'Og==') {
+ update reply {
+ Filter-ID += 'fail 9'
+ }
+}
+
+update request {
+ Tmp-String-0 := "%{base64:&Tmp-Cast-Short}"
+ Tmp-String-1 := "%{base64:&Tmp-Cast-Ethernet}"
+ Tmp-String-2 := "%{base64:&Tmp-Cast-Integer64}"
+ Tmp-String-3 := "%{base64:&Tmp-Cast-IPv4Prefix}"
+}
+
+# short - bin 0x373b
+if (Tmp-String-0 != 'Nzs=') {
+ update reply {
+ Filter-ID += 'fail 9'
+ }
+}
+
+# ethernet - bin 0x00003938373c
+if (Tmp-String-1 != 'AAA5ODc8') {
+ update reply {
+ Filter-Id += 'fail 10'
+ }
+}
+
+# integer64 - bin 0x100000003938373d
+if (Tmp-String-2 != 'EAAAADk4Nz0=') {
+ update reply {
+ Filter-Id += 'fail 11'
+ }
+}
+
+# ipv4prefix - bin 0x00203938373e
+if (Tmp-String-3 != 'ACA5ODc+') {
+ update reply {
+ Filter-Id += 'fail 12'
+ }
+}
--- /dev/null
+#
+# PRE: update if
+#
+update {
+ control:Cleartext-Password := 'hello'
+ request:NAS-IP-Address := 127.0.0.1
+ request:Tmp-Integer-0 := 2130706433
+}
+
+update request {
+ Tmp-String-0 := "%{request:NAS-IP-Address}"
+}
+
+if (<ipaddr>Tmp-Integer-0 == NAS-IP-Address) {
+ update reply {
+ Filter-Id := "filter"
+ }
+}
--- /dev/null
+#
+# PRE: update if xlat-attr-index
+#
+update request {
+ control:Cleartext-Password := 'hello'
+ Tmp-Octets-0 := 0x69206861766520736361727920656d626564646564207468696e67730020696e73696465206d65
+ Tmp-Octets-1 := 0x30783031013078303707307830410A307830440D222230786230b0C2b0
+ Tmp-String-0 := "i have scary embedded things\\000 inside me"
+ Tmp-String-0 += "0x01\0010x07\0070x0A\n0x0D\r\"\"0xb0\260°"
+ reply:Filter-Id := "filter"
+}
+
+if ("%{string:Tmp-Octets-0}" != 'i have scary embedded things\\000 inside me') {
+ update reply {
+ Filter-Id := 'fail'
+ }
+}
+
+if ("%{string:Tmp-Octets-1}" != '0x01\\0010x07\\0070x0A\\n0x0D\\r\\"\\"0xb0\\260°') {
+ update reply {
+ Filter-Id := 'fail'
+ }
+}
+
+if ("%{Tmp-String-0[0]}" != 'i have scary embedded things\\000 inside me') {
+ update reply {
+ Filter-Id := 'fail'
+ }
+}
+
+if ("%{Tmp-String-0[1]}" != '0x01\\0010x07\\0070x0A\\n0x0D\\r\\"\\"0xb0\\260°') {
+ update reply {
+ Filter-Id := 'fail'
+ }
+}
+
+# And another slightly different codepath...
+if ("%{Tmp-String-0[*]}" != 'i have scary embedded things\\000 inside me,0x01\\0010x07\\0070x0A\\n0x0D\\r\\"\\"0xb0\\260°') {
+ update reply {
+ Filter-Id := 'fail'
+ }
+}
+
+
foreach Filter-Id {
foreach Calling-Station-Id {
update reply {
- Called-Station-Id += "%{Foreach-Variable-0} %{Foreach-Variable-1}"
+ Called-Station-Id += "%{Foreach-Variable-0} %{Foreach-Variable-1}"
}
}
}
Filter-Id += "2"
Filter-Id += "3"
Filter-Id += "4"
-Calling-Station-Id = "foo"
+Calling-Station-Id = "foo\n"
Calling-Station-Id += "bar"
#
# Expected answer
#
Response-Packet-Type == Access-Accept
-Called-Station-Id == '1 foo'
+Called-Station-Id == '1 foo\n'
Called-Station-Id == '1 bar'
-Called-Station-Id == '2 foo'
+Called-Station-Id == '2 foo\n'
Called-Station-Id == '2 bar'
-Called-Station-Id == '3 foo'
+Called-Station-Id == '3 foo\n'
Called-Station-Id == '3 bar'
-Called-Station-Id == '4 foo'
+Called-Station-Id == '4 foo\n'
Called-Station-Id == '4 bar'
Called-Station-Id += "%{Foreach-Variable-0}"
}
}
+
+
+#
+# Adding attribute during request and immediately breaking
+#
+update {
+ request:Filter-Id += "1"
+ request:Filter-Id += "2"
+}
+
+foreach &request:Reply-Message {
+ if("%{Foreach-Variable-0}" == "1") {
+ update {
+ request:Filter-Id += "3"
+ }
+ break
+ }
+}
+
+update {
+ request:Filter-Id !* ANY
+}
+
+#
+# Adding attribute during request and continuing
+#
+update {
+ request:Filter-Id += "1"
+ request:Filter-Id += "2"
+}
+
+foreach &request:Reply-Message {
+ if("%{Foreach-Variable-0}" == "1") {
+ update {
+ request:Filter-Id += "3"
+ }
+ }
+
+ if ("%{Foreach-Variable-0}" == "3") {
+ break
+ }
+}
--- /dev/null
+foreach "%{expr:1 + 2}" { # ERROR
+ update reply {
+ Called-Station-Id += "%{Foreach-Variable-0}"
+ }
+}
--- /dev/null
+# PRE: foreach if-regex-match
+
+# This is what most people end up using foreach for,
+# so we should probably test it works.
+update request {
+ Tmp-String-0 := "cisco"
+}
+
+# Expanded regex
+foreach Cisco-AVPair {
+ if ("%{Foreach-Variable-0}" =~ /^%{Tmp-String-0}=(.*)$/i) {
+ update reply {
+ Called-Station-Id += "%{1}"
+ }
+ }
+}
+
+# Compiled regex
+foreach Cisco-AVPair {
+ if ("%{Foreach-Variable-0}" =~ /^stupid=(.*)$/i) {
+ update reply {
+ Called-Station-Id += "%{1}"
+ }
+ }
+}
+
--- /dev/null
+#
+# Input packet
+#
+User-Name = "bob"
+User-Password = "hello"
+Cisco-AVPair = "stupid=1"
+Cisco-AVPair += "retarded=2"
+Cisco-AVPair += "cisco=3"
+Cisco-AVPair += "shit=4"
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+Called-Station-Id == "3"
+Called-Station-Id == "1"
--- /dev/null
+#
+# PRE: update
+#
+update reply {
+ Filter-Id := "filter"
+}
+
+update request {
+ Tmp-String-0 := '9870'
+ Tmp-Octets-0 := 0x39383731
+ Tmp-IP-Address-0 := 57.56.55.50
+ Tmp-Date-0 := 959985459
+ Tmp-Integer-0 := 959985460
+ Tmp-Cast-Abinary := 'ip out forward srcip 57.56.55.53/32 udp dstport = 1812'
+ Tmp-Cast-IfId := '0000:0000:3938:3737'
+ Tmp-Cast-IPv6Addr := '::3938:3738'
+ Tmp-Cast-IPv6Prefix := '::3938:3739/128'
+ Tmp-Cast-Byte := 58
+ Tmp-Cast-Short := 14139
+ Tmp-Cast-Ethernet := 00:00:39:38:37:3c
+ Tmp-Cast-Integer64 := 1152921505566832445
+ Tmp-Cast-IPv4Prefix := 57.56.55.62/32
+}
+
+update request {
+ Tmp-String-0 := "%{hex:Tmp-String-0}"
+ Tmp-String-1 := "%{hex:Tmp-Octets-0}"
+ Tmp-String-2 := "%{hex:Tmp-IP-Address-0}"
+ Tmp-String-3 := "%{hex:Tmp-Date-0}"
+ Tmp-String-4 := "%{hex:Tmp-Integer-0}"
+ Tmp-String-5 := "%{hex:Tmp-Cast-Abinary}"
+ Tmp-String-6 := "%{hex:Tmp-Cast-Ifid}"
+ Tmp-String-7 := "%{hex:Tmp-Cast-IPv6Addr}"
+ Tmp-String-8 := "%{hex:Tmp-Cast-IPv6Prefix}"
+ Tmp-String-9 := "%{hex:Tmp-Cast-Byte}"
+}
+
+# String
+if (Tmp-String-0 != '39383730') {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+# Octets
+if (Tmp-String-1 != '39383731') {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+# IP Address
+if (Tmp-String-2 != '39383732') {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+# Date
+if (Tmp-String-3 != '39383733') {
+ update reply {
+ Filter-Id += 'fail 4'
+ }
+}
+
+# Integer
+if (Tmp-String-4 != '39383734') {
+ update reply {
+ Filter-Id += 'fail 5'
+ }
+}
+
+# Abinary
+if (Tmp-String-5 != '0101000039383735000000002000110000000714000200000000000000000000') {
+ update reply {
+ Filter-Id += 'fail 6'
+ }
+}
+
+# ifid
+if (Tmp-String-6 != '0000000039383737') {
+ update reply {
+ Filter-Id += 'fail 7'
+ }
+}
+
+# ipv6addr
+if (Tmp-String-7 != '00000000000000000000000039383738') {
+ update reply {
+ Filter-ID += 'fail 8'
+ }
+}
+
+# ipv6addrprefix
+if (Tmp-String-8 != '008000000000000000000000000039383739') {
+ update reply {
+ Filter-ID += 'fail 9'
+ }
+}
+
+# byte
+if (Tmp-String-9 != '3a') {
+ update reply {
+ Filter-ID += 'fail 10'
+ }
+}
+
+update request {
+ Tmp-String-0 := "%{hex:Tmp-Cast-Short}"
+ Tmp-String-1 := "%{hex:Tmp-Cast-Ethernet}"
+ Tmp-String-2 := "%{hex:Tmp-Cast-Integer64}"
+ Tmp-String-3 := "%{hex:Tmp-Cast-IPv4Prefix}"
+}
+
+# short
+if (Tmp-String-0 != '373b') {
+ update reply {
+ Filter-ID += 'fail 11'
+ }
+}
+
+# ethernet
+if (Tmp-String-1 != '00003938373c') {
+ update reply {
+ Filter-Id += 'fail 12'
+ }
+}
+
+# integer64
+if (Tmp-String-2 != '100000003938373d') {
+ update reply {
+ Filter-Id += 'fail 13'
+ }
+}
+
+# ipv4prefix
+if (Tmp-String-3 != '00203938373e') {
+ update reply {
+ Filter-Id += 'fail 14'
+ }
+}
# PRE: if
#
-# May as well exercise the regular expression engine
-if (User-Name =~ /^([0-9])_([0-9])?_([0-9]*)_([0-9]+)_([^_])_(6)_([7-8])/) {
+
+# Non matching on attribute ref
+if (User-Name !~ /^([0-9])_([0-9])?_([0-9]*)_([0-9]+)_([^_])_(6)_([7-8])%{Tmp-String-0}/) {
+ update reply {
+ Filter-Id += 'Fail 0'
+ }
+}
+
+# Matching on xlat expanded value
+if ("%{User-Name}" !~ /^([0-9])_([0-9])?_([0-9]*)_([0-9]+)_([^_])_(6)_([7-8])%{Tmp-String-0}/) {
+ update reply {
+ Filter-Id += 'Fail 1'
+ }
+}
+
+# Matching on attribute ref with capture groups
+if (User-Name =~ /^([0-9])_([0-9])?_([0-9]*)_([0-9]+)_([^_])_(6)_([7-8])%{Tmp-String-0}/) {
+ # Test all the capture groups
update {
reply:User-Name := "%{7}_%{6}_%{5}_%{4}_%{3}_%{2}_%{1}_%{0}"
}
}
+else {
+ update reply {
+ Filter-Id += 'Fail 2'
+ }
+}
+
+# Checking capture groups are cleared out correctly
+if (User-Name =~ /^([0-9])_%{Tmp-String-0}/) {
+ if ("%{0}%{1}%{2}%{3}%{4}%{5}%{6}%{7}" != '1_1') {
+ update reply {
+ Filter-Id += 'Fail 3'
+ }
+ }
+}
+else {
+ update reply {
+ Filter-Id += 'Fail 3.5'
+ }
+}
+
+# Checking capture groups are cleared out correctly when there are no matches
+if (User-Name =~ /^.%{Tmp-String-0}/) {
+ if ("%{0}%{1}%{2}%{3}%{4}%{5}%{6}%{7}" != '1') {
+ update reply {
+ Filter-Id += 'Fail 4'
+ }
+ }
+}
+else {
+ update reply {
+ Filter-Id += 'Fail 4.5'
+ }
+}
+
+# uncompiled - ref - insensitive
+if (Calling-Station-Id !~ /:roamyroam%{Tmp-String-0}$/i) {
+ update reply {
+ Filter-Id += 'Fail 5'
+ }
+}
+
+# uncompiled - expansion - insensitive
+if ("%{Calling-Station-Id}" !~ /:roamyroam%{Tmp-String-0}$/i) {
+ update reply {
+ Filter-Id += 'Fail 6'
+ }
+}
+
+# uncompiled - enum - ref - insensitive
+if (Service-Type !~ /^framed-user%{Tmp-String-0}$/i) {
+ update reply {
+ Filter-Id += 'Fail 7'
+ }
+}
+
+# uncompiled - enum - expansion - insensitive
+if ("%{Service-Type}" !~ /^framed-user%{Tmp-String-0}$/i) {
+ update reply {
+ Filter-Id += 'Fail 8'
+ }
+}
+
+# uncompiled - enum - ref
+if (Service-Type =~ /^framed-user%{Tmp-String-0}$/) {
+ update reply {
+ Filter-Id += 'Fail 9'
+ }
+}
+
+
+
--- /dev/null
+# PRE: if
+#
+
+# Non matching on attribute ref
+if (User-Name !~ /^([0-9])_([0-9])?_([0-9]*)_([0-9]+)_([^_])_(6)_([7-8])/) {
+ update reply {
+ Filter-Id += 'Fail 0'
+ }
+}
+
+# Matching on xlat expanded value
+if ("%{User-Name}" !~ /^([0-9])_([0-9])?_([0-9]*)_([0-9]+)_([^_])_(6)_([7-8])/) {
+ update reply {
+ Filter-Id += 'Fail 1'
+ }
+}
+
+# Matching on attribute ref with capture groups
+if (User-Name =~ /^([0-9])_([0-9])?_([0-9]*)_([0-9]+)_([^_])_(6)_([7-8])/) {
+ # Test all the capture groups
+ update {
+ reply:User-Name := "%{7}_%{6}_%{5}_%{4}_%{3}_%{2}_%{1}_%{0}"
+ }
+}
+else {
+ update reply {
+ Filter-Id += 'Fail 2'
+ }
+}
+
+# Checking capture groups are cleared out correctly
+if (User-Name =~ /^([0-9])_/) {
+ if ("%{0}%{1}%{2}%{3}%{4}%{5}%{6}%{7}" != '1_1') {
+ update reply {
+ Filter-Id += 'Fail 3'
+ }
+ }
+}
+else {
+ update reply {
+ Filter-Id += 'Fail 3.5'
+ }
+}
+
+# Checking capture groups are cleared out correctly when there are no matches
+if (User-Name =~ /^./) {
+ if ("%{0}%{1}%{2}%{3}%{4}%{5}%{6}%{7}" != '1') {
+ update reply {
+ Filter-Id += 'Fail 4'
+ }
+ }
+}
+else {
+ update reply {
+ Filter-Id += 'Fail 4.5'
+ }
+}
+
+# compiled - ref - insensitive
+if (Calling-Station-Id !~ /:roamyroam$/i) {
+ update reply {
+ Filter-Id += 'Fail 5'
+ }
+}
+
+# compiled - expansion - insensitive
+if ("%{Calling-Station-Id}" !~ /:roamyroam$/i) {
+ update reply {
+ Filter-Id += 'Fail 6'
+ }
+}
+
+# compiled - enum - ref - insensitive
+if (Service-Type !~ /^framed-user$/i) {
+ update reply {
+ Filter-Id += 'Fail 7'
+ }
+}
+
+# compiled - enum - expansion - insensitive
+if ("%{Service-Type}" !~ /^framed-user$/i) {
+ update reply {
+ Filter-Id += 'Fail 8'
+ }
+}
+
+# compiled - enum - ref
+if (Service-Type =~ /^framed-user$/) {
+ update reply {
+ Filter-Id += 'Fail 9'
+ }
+}
+
+
--- /dev/null
+User-Name = '1_2_3_4_5_6_7'
+User-Password = 'hello'
+Service-Type := 'Framed-User'
+Calling-Station-ID := '00:11:22:33:44:55:66:ROAMYROAM'
+
+Response-Packet-Type == Access-Accept
+User-Name == '7_6_5_4_3_2_1_1_2_3_4_5_6_7'
User-Name = '1_2_3_4_5_6_7'
User-Password = 'hello'
+Service-Type := 'Framed-User'
+Calling-Station-ID := '00:11:22:33:44:55:66:ROAMYROAM'
Response-Packet-Type == Access-Accept
User-Name == '7_6_5_4_3_2_1_1_2_3_4_5_6_7'
# Conditions which statically evaluate to "false"
# have their entire contents skipped on load.
#
+# Conditions which statically evaluate to "true"
+# have the following "else" sections skipped, too.
+#
# i.e. we can reference things which don't exist,
# and they'll get ignored.
#
if (0) {
- no-such-module
+ no-such-module
+}
+
+if (0) {
+ no-such-module
+}
+else {
+ ok
+}
+
+if (1) {
+ ok
+}
+else {
+ no-such-module
+}
+
+if (1) {
+ ok
+}
+elsif ("%{foo:bar}") { # no pass2
+ no-such-module
+}
+else {
+ no-such-module
}
update reply {
--- /dev/null
+#
+# PRE: update
+#
+update reply {
+ Filter-Id := "filter"
+}
+
+update request {
+ Tmp-String-0 := '9870'
+ Tmp-String-1 := '98709870'
+ Tmp-String-2 := '987098709870'
+ Tmp-Octets-0 := 0x39383731
+ Tmp-Octets-1 := 0x3938373139383731
+ Tmp-Octets-2 := 0x393837313938373139383731
+ Tmp-IP-Address-0 := 57.56.55.50
+ Tmp-Date-0 := 959985459
+ Tmp-Integer-0 := 959985460
+ Tmp-Cast-Abinary := 'ip out forward srcip 57.56.55.53/32 udp dstport = 1812'
+ Tmp-Cast-IfId := '0000:0000:3938:3737'
+ Tmp-Cast-IPv6Addr := '::3938:3738'
+ Tmp-Cast-IPv6Prefix := '::3938:3739/128'
+ Tmp-Cast-Byte := 58
+ Tmp-Cast-Short := 14139
+ Tmp-Cast-Ethernet := 00:00:39:38:37:3c
+ Tmp-Cast-Integer64 := 1152921505566832445
+ Tmp-Cast-IPv4Prefix := 57.56.55.62/32
+}
+
+update request {
+ Tmp-String-2 := "%{integer:Tmp-IP-Address-0}"
+ Tmp-String-3 := "%{integer:Tmp-Date-0}"
+ Tmp-String-4 := "%{integer:Tmp-Integer-0}"
+ Tmp-String-5 := "%{integer:Tmp-Cast-Abinary}"
+ Tmp-String-6 := "%{integer:Tmp-Cast-Ifid}"
+ Tmp-String-7 := "%{integer:Tmp-Cast-IPv6Addr}"
+ Tmp-String-8 := "%{integer:Tmp-Cast-IPv6Prefix}"
+}
+
+# String - network order representation of a 4 char string
+update request {
+ Tmp-Integer-0 := "%{integer:Tmp-String-0}"
+}
+if ((Tmp-String-0 != "%{string:Tmp-Integer-0}") || (Tmp-Integer-0 != 959985456)) {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+# String - network order representation of a 8 char string
+update request {
+ Tmp-Integer64-0 := "%{integer:Tmp-String-1}"
+}
+if ((Tmp-String-1 != "%{string:Tmp-Integer64-0}") || (Tmp-Integer64-0 != 4123106139115632432)) {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+# String - Can't convert 12 byte string to integer (our biggest native size is a 64bit unsigned int)
+if ("%{integer:Tmp-String-2}" != '') {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+# Octets - network order representation of a 4 byte octet string
+update request {
+ Tmp-Integer-0 := "%{integer:Tmp-Octets-0}"
+}
+if ((Tmp-Octets-0 != "0x%{hex:Tmp-Integer-0}") || (Tmp-Integer-0 != 959985457)) {
+ update reply {
+ Filter-Id += 'fail 4'
+ }
+}
+
+# Octets - network order representation of a 8 byte octet string
+update request {
+ Tmp-Integer64-0 := "%{integer:Tmp-Octets-1}"
+}
+if ((Tmp-Octets-1 != "0x%{hex:Tmp-Integer64-0}") || (Tmp-Integer64-0 != 4123106143410599729)) {
+ update reply {
+ Filter-Id += 'fail 5'
+ }
+}
+
+# String - Can't convert 12 byte octet string to integer (our biggest native size is a 64bit unsigned int)
+if ("%{integer:Tmp-Octets-2}" != '') {
+ update reply {
+ Filter-Id += 'fail 6'
+ }
+}
+
+# IP Address
+if (Tmp-String-2 != '959985458') {
+ update reply {
+ Filter-Id += 'fail 7'
+ }
+}
+
+if (<ipaddr>Tmp-String-2 != &Tmp-IP-Address-0) {
+ update reply {
+ Filter-Id += 'fail 8'
+ }
+}
+
+# Date
+if (Tmp-String-3 != '959985459') {
+ update reply {
+ Filter-Id += 'fail 9'
+ }
+}
+
+# Integer
+if (Tmp-String-4 != '959985460') {
+ update reply {
+ Filter-Id += 'fail 10'
+ }
+}
+
+# Abinary - Can't convert ascend binary to an integer
+if (Tmp-String-5 != '') {
+ update reply {
+ Filter-Id += 'fail 11'
+ }
+}
+
+# ifid - Can't convert interface ID to an integer
+if (Tmp-String-6 != '') {
+ update reply {
+ Filter-Id += 'fail 12'
+ }
+}
+
+# ipv6addr - Can't convert IPv6 to integer
+if (Tmp-String-7 != '959985464') {
+ update reply {
+ Filter-ID += 'fail 13'
+ }
+}
+
+# ipv6addrprefix
+if (Tmp-String-8 != '959985465') {
+ update reply {
+ Filter-ID += 'fail 14'
+ }
+}
+update request {
+ Tmp-String-0 := "%{integer:Tmp-Cast-Byte}"
+ Tmp-String-1 := "%{integer:Tmp-Cast-Short}"
+ Tmp-String-2 := "%{integer:Tmp-Cast-Ethernet}"
+ Tmp-String-3 := "%{integer:Tmp-Cast-Integer64}"
+ Tmp-String-4 := "%{integer:Tmp-Cast-IPv4Prefix}"
+}
+
+# byte
+if (Tmp-String-0 != '58') {
+ update reply {
+ Filter-ID += 'fail 15'
+ }
+}
+
+# short
+if (Tmp-String-1 != '14139') {
+ update reply {
+ Filter-ID += 'fail 16'
+ }
+}
+
+# ethernet
+if (Tmp-String-2 != '62913607630848') {
+ update reply {
+ Filter-Id += 'fail 17'
+ }
+}
+if (<ether>Tmp-String-2 != &Tmp-Cast-Ethernet) {
+ update reply {
+ Filter-Id += 'fail 18'
+ }
+}
+
+# integer64
+if (Tmp-String-3 != '1152921505566832445') {
+ update reply {
+ Filter-Id += 'fail 19'
+ }
+}
+
+# ipv4prefix
+if (Tmp-String-4 != '959985470') {
+ update reply {
+ Filter-Id += 'fail 20'
+ }
+}
+
+
+
+
--- /dev/null
+#
+# PRE: update if
+#
+update control {
+ Cleartext-Password := 'hello'
+}
+
+update reply {
+ Filter-Id := "filter"
+}
+
+update control {
+ Tmp-Cast-IPv4Prefix := 198.51.100.255/16
+ Tmp-Cast-IPv6Prefix := ::198.51.100.255/112
+}
+
+if ("%{control:Tmp-Cast-IPv6Prefix}" != '::198.51.0.0/112') {
+ update reply {
+ Filter-Id += "wrong"
+ }
+}
+
+if ("%{control:Tmp-Cast-IPv4Prefix}" != '198.51.0.0/16') {
+ update reply {
+ Filter-Id += "wrong"
+ }
+}
+
+if (control:Tmp-Cast-IPv6Prefix != ::198.51.0.0/112) {
+ update reply {
+ Filter-Id += "wrong"
+ }
+}
+
+if (control:Tmp-Cast-IPv4Prefix != 198.51.0.0/16) {
+ update reply {
+ Filter-Id += "wrong"
+ }
+}
--- /dev/null
+#
+# PRE: hex
+#
+update reply {
+ Filter-Id := "filter"
+}
+
+update request {
+ Tmp-String-0 := '\
+abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\
+abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\
+abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz'
+ Tmp-String-2 := '9870'
+ Tmp-Octets-0 := 0x39383731
+ Tmp-IP-Address-0 := 57.56.55.50
+ Tmp-Date-0 := 959985459
+ Tmp-Integer-0 := 959985460
+ Tmp-Cast-Abinary := 'ip out forward srcip 57.56.55.53/32 udp dstport = 1812'
+ Tmp-Cast-IfId := '0000:0000:3938:3737'
+ Tmp-Cast-IPv6Addr := '::3938:3738'
+ Tmp-Cast-IPv6Prefix := '::3938:3739/128'
+ Tmp-Cast-Byte := 58
+ Tmp-Cast-Short := 14139
+ Tmp-Cast-Ethernet := 00:00:39:38:37:3c
+ Tmp-Cast-Integer64 := 1152921505566832445
+ Tmp-Cast-IPv4Prefix := 57.56.55.62/32
+}
+
+update request {
+ Tmp-Integer-0 := "%{length:Tmp-String-0}"
+}
+
+if (Tmp-Integer-0 != 260) {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+update request {
+ Tmp-Integer-0 := "%{length:Tmp-String-2}"
+ Tmp-Integer-1 := "%{length:Tmp-Octets-0}"
+ Tmp-Integer-2 := "%{length:Tmp-IP-Address-0}"
+ Tmp-Integer-3 := "%{length:Tmp-Date-0}"
+ Tmp-Integer-4 := "%{length:Tmp-Integer-0}"
+ Tmp-Integer-5 := "%{length:Tmp-Cast-Abinary}"
+ Tmp-Integer-6 := "%{length:Tmp-Cast-Ifid}"
+ Tmp-Integer-7 := "%{length:Tmp-Cast-IPv6Addr}"
+ Tmp-Integer-8 := "%{length:Tmp-Cast-IPv6Prefix}"
+ Tmp-Integer-9 := "%{length:Tmp-Cast-Byte}"
+}
+
+# String - bin 0x39383730
+if (Tmp-Integer-0 != 4) {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+# Octets - bin 0x39383731
+if (Tmp-Integer-1 != 4) {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+# IP Address - bin 0x39383732
+if (Tmp-Integer-2 != 4) {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+# Date - bin 0x39383733
+if (Tmp-Integer-3 != 4) {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+# Integer - bin 0x39383734
+if (Tmp-Integer-4 != 4) {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+# Abinary - bin 0x0101000039383735000000002000110000000714000200000000000000000000
+if (Tmp-Integer-5 != 32) {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+# ifid - bin 0x0000000039383737
+if (Tmp-Integer-6 != 8) {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+# ipv6addr - bin 0x00000000000000000000000039383738
+if (Tmp-Integer-7 != 16) {
+ update reply {
+ Filter-ID += 'fail'
+ }
+}
+
+# ipv6addrprefix - bin 0x008000000000000000000000000039383739
+if (Tmp-Integer-8 != 18) {
+ update reply {
+ Filter-ID += 'fail'
+ }
+}
+
+# byte - bin 0x3a
+if (Tmp-Integer-9 != 1) {
+ update reply {
+ Filter-ID += 'fail'
+ }
+}
+
+update request {
+ Tmp-Integer-0 := "%{length:Tmp-Cast-Short}"
+ Tmp-Integer-1 := "%{length:Tmp-Cast-Ethernet}"
+ Tmp-Integer-2 := "%{length:Tmp-Cast-Integer64}"
+ Tmp-Integer-3 := "%{length:Tmp-Cast-IPv4Prefix}"
+}
+
+# short - bin 0x373b
+if (Tmp-Integer-0 != 2) {
+ update reply {
+ Filter-ID += 'fail'
+ }
+}
+
+# ethernet - bin 0x00003938373c
+if (Tmp-Integer-1 != 6) {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+# integer64 - bin 0x100000003938373d
+if (Tmp-Integer-2 != 8) {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+# ipv4prefix - bin 0x00203938373e
+if (Tmp-Integer-3 != 6) {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
#
# PRE: update if
#
+update reply {
+ Filter-Id := "filter"
+}
+
update {
control:Cleartext-Password := 'hello'
- request:Called-Station-Id := "%{md5:This is a string\n}"
+ request:Tmp-String-0 := "This is a string\n"
+ request:Tmp-Octets-0 := 0x000504030201
}
#
# Put "This is a string" into a file and call "md5sum" on it.
# You should get this string.
#
-if (Called-Station-Id == "9ac4dbbc3c0ad2429e61d0df5dc28add") {
+if ("%{md5:This is a string\n}" != '9ac4dbbc3c0ad2429e61d0df5dc28add') {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+if ("%{md5:&Tmp-String-0}" != '9ac4dbbc3c0ad2429e61d0df5dc28add') {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+if ("%{md5:&request:Tmp-String-0}" != '9ac4dbbc3c0ad2429e61d0df5dc28add') {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+# This differs than hashing the attribute directly, as the \n is escaped and becomes chars \ and n
+if ("%{md5:%{request:Tmp-String-0}}" != 'b41832e1bd19528e1a09495922182579') {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+#
+# MD5 should also be able to cope with references to octet attributes
+#
+if ("%{md5:&request:Tmp-Octets-0}" != 'c1e7fa505b2fc1fd0da6cac3db6f6f44') {
update reply {
- Filter-Id := "filter"
+ Filter-Id += 'fail'
}
}
raddb = raddb
keyword = src/tests/keywords
-modconfdir = ${raddb}/mods-config
+modconfdir = ${raddb}/mods-config
+
+# Only for testing!
+# Setting this on a production system is a BAD IDEA.
+security {
+ allow_vulnerable_openssl = yes
+}
modules {
$INCLUDE ${raddb}/mods-enabled/always
}
authenticate {
- pap
+ pap
}
}
--- /dev/null
+#
+# PRE: if-regex-match
+#
+
+#
+# Check that bad regular expressions will fail
+#
+if (&User-Name =~ /[a-3]/) { # ERROR
+ update reply {
+ Filter-Id := "filter"
+ }
+}
#
update {
control:Cleartext-Password := 'hello'
- request:Called-Station-Id := "%{sha1:This is a string\n}"
+ request:Tmp-String-0 := "This is a string\n"
+ request:Tmp-Octets-0 := 0x000504030201
+}
+
+update reply {
+ Filter-Id := 'filter'
}
#
# Put "This is a string" into a file and call "sha1sum" on it.
# You should get this string.
#
-if (Called-Station-Id == "cc7edf1ccc4bdf1e0ec8f72b95388b65218ecf0c") {
+if ("%{sha1:This is a string\n}" != 'cc7edf1ccc4bdf1e0ec8f72b95388b65218ecf0c') {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+if ("%{sha1:&Tmp-String-0}" != 'cc7edf1ccc4bdf1e0ec8f72b95388b65218ecf0c') {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+if ("%{sha1:&request:Tmp-String-0}" != 'cc7edf1ccc4bdf1e0ec8f72b95388b65218ecf0c') {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+# This differs than hashing the attribute directly, as the \n is escaped and becomes chars \ and n
+if ("%{sha1:%{Tmp-String-0}}" != 'd79c6dae2d4b3f4d78d0c044b38e23f52f376726') {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+#
+# SHA1 should also be able to cope with references to octet attributes
+#
+if ("%{sha1:&request:Tmp-Octets-0}" != '365b244645fe7294dff062174996572319d5a82c') {
update reply {
- Filter-Id := "filter"
+ Filter-Id += 'fail'
}
}
--- /dev/null
+#
+# PRE: update if
+#
+if ("$ENV{OPENSSL_LIBS}" != "") {
+
+update {
+ control:Cleartext-Password := 'hello'
+ request:Tmp-String-0 := "This is a string\n"
+ request:Tmp-Octets-0 := 0x000504030201
+}
+
+update reply {
+ Filter-Id := 'filter'
+}
+
+#
+# Put "This is a string" into a file and call "sha256sum" on it.
+# You should get this string.
+#
+if ("%{sha256:This is a string\n}" != 'b3716a1ab53042bb392034f29071e13b0c38aa19b4edd75d9a76022f91189124') {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+if ("%{sha256:&Tmp-String-0}" != 'b3716a1ab53042bb392034f29071e13b0c38aa19b4edd75d9a76022f91189124') {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+if ("%{sha256:&request:Tmp-String-0}" != 'b3716a1ab53042bb392034f29071e13b0c38aa19b4edd75d9a76022f91189124') {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+# This differs than hashing the attribute directly, as the \n is escaped and becomes chars \ and n
+if ("%{sha256:%{Tmp-String-0}}" != 'd1a16b1ef3a074dcd82cbce40590838e4627f5da371618e4d7f9de3786600bb9') {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+#
+# SHA256 should also be able to cope with references to octet attributes
+#
+if ("%{sha256:&request:Tmp-Octets-0}" != 'f307e202b881fded70e58017aa0c4d7b29c76ab25d02bf078301a5f6635187eb') {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+#
+# SHA512 and SHA256 share common code paths, so the tests don't need to be
+# as exhaustive.
+#
+if ("%{sha512:This is a string\n}" != '56b57df5cce42d4e35c644649798ea23ec16f4f4626e78faf4d2d8f430ea349bcc28cd5532457c82f0aa66bf68988346039fe75b900a92ff94fd53993d45990f') {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+if ("%{sha512:&Tmp-String-0}" != '56b57df5cce42d4e35c644649798ea23ec16f4f4626e78faf4d2d8f430ea349bcc28cd5532457c82f0aa66bf68988346039fe75b900a92ff94fd53993d45990f') {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+if ("%{sha512:&request:Tmp-Octets-0}" != 'de80271eb5e03a1c24dd0cd823a22305a743ee3a54f1de5bf97adbf56984561154bfb6928b1da4ccc3f5dde9f4032ad461937b60b9ace4ad3898cf45c90596d7') {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+}
+
+else { # no OPENSSL. Force the test to pass
+ update reply {
+ Filter-Id := 'filter'
+ }
+}
-switch User-Name {
+switch &User-Name {
case "bob" {
update reply {
Filter-Id := "filter"
Filter-Id := "default"
}
}
-
-}
\ No newline at end of file
+}
--- /dev/null
+#
+# PRE: switch switch-attr-cmp
+#
+
+update request {
+ Service-Type := Login-User
+ Filter-Id := "Login-User"
+}
+
+switch &Service-Type {
+ case "%{expr: 1 + 2}" {
+ update reply {
+ Filter-Id := "3"
+ }
+ }
+
+ #
+ # The Filter-Id will get printed to a string,
+ # have the string parsed as a Service-Type attr,
+ # and then that compared to the input Service-Type
+ #
+ case &Filter-Id {
+ update reply {
+ Filter-Id := "filter"
+ }
+ }
+
+ case {
+ update reply {
+ Filter-Id := "default"
+ }
+ }
+
+}
--- /dev/null
+#
+# PRE: switch
+#
+update request {
+ Tmp-String-0 := &User-Name
+}
+
+#
+# A switch statement where we compare two attributes
+#
+switch &User-Name {
+ case &Tmp-String-0 {
+ update reply {
+ Filter-Id := "filter"
+ }
+ }
+
+ case "doug" {
+ update reply {
+ Filter-Id := "doug"
+ }
+ }
+
+ case {
+ update reply {
+ Filter-Id := "default"
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+#
+# PRE: switch
+#
+switch &Service-Type {
+ case "%{expr: 1 + 2}" {
+ update reply {
+ Filter-Id := "3"
+ }
+ }
+
+ case Login-User {
+ update reply {
+ Filter-Id := "Login-User"
+ }
+ }
+
+ case No-Such-Value { # ERROR
+ update reply {
+ Filter-Id := "FAILED"
+ }
+ }
+
+ case {
+ update reply {
+ Filter-Id := "default"
+ }
+ }
+
+}
--- /dev/null
+#
+# PRE: switch-value-error
+#
+# The same as "switch-value-error", but the attribute
+# is hidden inside of an xlat expansion. We now turn
+# simple attribute xlats into templates.
+#
+switch "%{Service-Type}" { # ERROR
+ case "%{expr: 1 + 2}" {
+ update reply {
+ Filter-Id := "3"
+ }
+ }
+
+ case Login-User {
+ update reply {
+ Filter-Id := "Login-User"
+ }
+ }
+
+ case {
+ update reply {
+ Filter-Id := "default"
+ }
+ }
+
+}
--- /dev/null
+#
+# PRE: switch
+#
+switch &User-Name {
+ case "%{no-such-module:bob}" { # ERROR
+ update reply {
+ Filter-Id := "fail"
+ }
+ }
+
+ case {
+ update reply {
+ Filter-Id := "default"
+ }
+ }
+
+}
--- /dev/null
+# cat /dev/urandom | env LC_CTYPE=C tr -cd 'a-f0-9' | head -c <n>
+
+update reply {
+ Filter-Id := "filter"
+}
+
+# 8192 - 0x (2) - '' (2) there are unlikely to be any static buffers this big outside of the conffile parser
+update request {
+ Tmp-Octets-0 := '0x\
+d8abccb7834711af1de1812be2579febe946f5d7beef6fa5c7074c0cb917e9b91e23e14b016f27610097c16c0e0fad88176e077b24198c770746159\
+05b8810d1c8b774d98889fa5c6027cde5e9c56dd4f7c48298c7713aeca5ba5dcfd506032ad05b1396f50e825b633d5a6af0dce6181b640287e03a65\
+8734df46a86341556f28455b3f377313a5a2ac8c8267b8a5de559b95f9b493a68b9e0278485f9e3914d702b2b7b90ee85ff393461f197386d09b836\
+5a8ae85ea025aea095f5d834c2ddf21e9a16b945da03c97f8a52687f19c605af9a245878b4bc5ed15b7937371ad629081159cf7de613d02c43f5cab\
+3529abbe61a6da1e55c685c2310c8eccb452f9758bf63fddfa58cdffb5cbf912f90e628310978dd1b3b7c2d3a08dd7ca6ca51081a114b013cc9d4c1\
+9f5ce0b1af81166c9402c105019a0fa9d15996c4f3d5fa35226bf88166598ff4f619322866df276d8b92fad06d120470c29217d29abb96ff861751e\
+acebbe839e28287c8cd485769d9a09e5bab524bde5776e15037d19503a2d032658e21aec7090032707ba0d662fcfa99e5e5ec183f8c63c6022bf281\
+22cf090fb80263f70c523aa0e00dd9f610c5b669754092253edd6f83b57bdd7a251514cdd99ab86cfa98b11469d1d1118aba0a149db6f0ccceb2f17\
+06bf33f657c7b8547dc284dfc10fdc1678c184901aa17f756d18df43409e1c4ead239cb78c46a9c412ccb097bba2244bb680bb249c15004d796731f\
+3890c1f94d8e0eda81487da9a65f817b5dbac4e639fce063f61a7db87d8b9d4b855120f56c3a0d57cb61ced57092506da881337280a18b2729717f5\
+133978362ca7941f9dbe9462ae5a46886c4d3c51b633278d6ad58a331c95e481cbbae866f046cb1a59ae2545fa32b12d4772244fd24bb91f7611d0c\
+beffbc5dee309c671fb5a171eacf45b20641e1cb4db306965eb43e98cb900ee805065c7adf4db3cdb97bbf8116dbb29f5ac07c7041a5f02d1a4fd1f\
+a7be6da388146d6b80ae8e152ac873cbf1f88c98cdd2e1de02df76461a1c50139f558f43ac1a91824fc48ea35976fab29d412f1ad990e528893ad4c\
+b6045b63d2a7af0657f1c348302e674ef0b39bd689b3b33dd3664c3e2386d0ea3241e70d2a2990b6243638d68033cc6040758e11f82ef783db2ae94\
+d2a8dbccd25fe2dce554837a2ca424199e4bd5442215623a77bffd603b575c847f88763fff1d6d0ff314851b1af06f99fb44d0a3115ad4389462452\
+c2331be24d486f6b5f2224cdfe44909e0a3bec47cdf6fe49fa60518e37950f986677e7f45617adcb20bc02990d3fe60de54ad2d1950bdd423e752c4\
+60f4eeaf2eeece07f3dea26db63cc0bc222a6f3228131cdb3360b9ec7e8f861c3e0bc822f9da00fef17f44ab4de7c166e5cb07d5c671f0364d4bccb\
+dc7f24868e066998bc8b3ab9052171b967162d536082b0a11c24f263c0e5f656b8349f970124af712cf098e8b08910aefcf7d42dd8a74e84ae6f9c4\
+006aa09483715b514833291c9d2e2bcdda567a16a493ac4fa17d5dff7a04b9f7f967febe7a8bdf911b1b668716be73fbf6f2416609224494dca1a18\
+1c1c7bb298671d39bdc1f664c833c9d2d4c08a65866db885929611fcd0c33139bc2959a865cbb686694896b539daa1db265ba78298cb3a09a331ef0\
+1423a7fd04b38ccdfbf1182a493c7a53c720a2dcf486249ff2b674341e77c2c0d5eb78efc07f295d562a77667457df58ea419c488680b9ce51aac01\
+4cd78984f70f29aec2a9b77fd45d38e0b07257b71f2146ccb11cd07681cbfff787b39b7ce9c42ce60513eccec2b490c68378e86bd441735b30410be\
+8710e71b2a326bd8b929abde80f25a0adb312f8ed5bb748866ddd8fb5fa81855d194afbdb1d511be453e21ab3f6481e47fa86b0697342706f85b8e8\
+84c6bf427390ef4c62532797de25004bb9d293e196ed29950e14682c68a8b6ab7c03256bc493b61eb3e44dc16726fcedb6c6776e2e9e0b3450fe6c6\
+24eef42e4806ef7c8abc367b7f1c83b7955ff6579d03362b428ca7711d228cf88402b60fd162ef4819216b9db66b4a1b0a5e0651a7901290eafa3d5\
+c698e40f73b3d66345d9e328d50ef2c767d370879890980d0d989de122ab22d7ef9979832b022e676eba4630d49434ec70025b44cb7146f9688d102\
+ceb55e6ca8ee9b9a66327da80f46367f452de7e2a84bf702b155539c7fa488d86c83faf3f150fda6d75eb476e2c31d73cea88148d9f02d178b0c098\
+5b4061830231ca405fbf41547ed9c036f53fc706b0fd1bb084e84a9e6dec81b4b4eea46c5ea26e99993ee930ccfeff4a185ffbce8a937243fa4734b\
+c24abbf465b0cd1f87686d44762140b5dfe57ae904cd8ed121f055d8a1bbf9c8a977133215f135e563b935451a7f797e72ef8f96390bc2477ad7aac\
+d2679557bac3b9a030926ff0801cc692dd641cf4f8a7bd9bdee21cdab3f7fbcf7d1d0de51101c5d816b19db49109958a8e75662ac700653112cd86c\
+10cbf45d3ea16f861de2d46714dfba8a34c1ad7ed4d5484802270187c3c7f70f7a51858479d8504e3b6267194404011b416329401ec55940f890f33\
+97d4bb3eab46990a4a03cdae9951ccd0bd42584ec88262f7d80193f09843c1fca7627b9cf708c646e84883b19fe3a8987912d04f1c0d1c779b740a7\
+fea0270374416a3987dd91d706e22e8c9698ef870d7f80d1c3042914a34736c185e542976d0145531c8eb20c3a6c5a5f747e97228ff55425fd93222\
+2d802ca36ac61555f69be4d645532579ddadb24a821f0bab1fb1f3b724ed4759b5303fe0015626ad00879e1a363d5e8b3aa0b7f3e572df3dc5f7352\
+7eb30b78e70dbe6ca81052315925d3892485168dd6f900289d1a0f9285e52988480bfda6a2c8b28cbd175b4dec735240c8f79afd5c93ed058da5551\
+8f20fb09edf4b4112c352604876f4083b68e534874d0b9ce2f977be2bcea0f9c123e119a70d269bc26ece608c39c98dbb069118148b01e403c16076\
+330b5d7929a7a7d724a7030d514ff0e38bee78e0044ffa508fc9793d7fc59075fd825e68d34e58568bffd8b20791862a8d0686763e49f1e3ed8a728\
+e33bb32a57c6374d153f93ba3cd283ce0af9a0a3b0ced4f83e3d604ff66f6584a35b51938ff4a0282c51f6f8561bd77b842ed0fd39fc43be825652f\
+f2c021f2b4d2b8c8ed2cf8eeb16f86863e59b374eda5a17e1bfc0b5a54169dd3e62b84a81bc1afd5cc3a1b193484428bcc3afb5344da990697f6787\
+5f72bc1ab04f52f75bc671b8d1239fc811d44032822abc95f8ea3465cdabdce5f83d5895d50fcbd97ad88e6b193172a4cf5f51814d9348498b1736e\
+de25f8b5afc8556d3b9573cb2ae8f51e8f0bca2f048d883592c9ab317e87864d48ca901e2aa2774360c77ba3f0a76c21f10155e32e91a2239d00e6b\
+0279bbc8977fadbea04b7b67575437fd5f6611a8889ecbde5fe45fcab8db9b62e831aadcd0ade54a94d30b6963d727979c116ef9f4a9a16a0e7a76e\
+d4f1177ad0ac7022beb12581629a7fd36c8ca5eeaa40d1a0d88cb0f701b288baae6c00a74c0b0dc3ffa6e9710bf3264684c1b9ff220710b2348cc93\
+d658d9eddae36232a0d0e06439d5dafdc7271eafbb3d16a17e36de7470c7a5ed034d735e2c216073ba6b4be7b319718d5afbd634684f5468d26afd0\
+63edfbc7fe6c8e98914eff397fcfdf44a10b84ba90b30d1a5da6823aab1792d666b32bdd0516ce3590c5dc2b49a6eabdb28cdc72dbc24e60ba0883f\
+953f0a99d29c1089b06063588b8bd965ba42e27f618d2b046fb3db93161981bbcd67fc965b0084ac25993445732b52d18cd2868e6b545214a2d501a\
+0002d2043d9a9790905dde296f16517e295dd295a97991c205d50dba331e86f06b0195e52fdd21f8e65e6b00fe7165e1a951805e5947aaee125f180\
+a2127375d8898aba1af3a3db34470e78bed99917a6bb87725788c1e2c8f35d6022d51bafdc3e69673cbdd80dc9cfde7dc1bd06e3a6437c720cb7b6c\
+2b3bc808111593d5f2a88c6e5b499c51155f4ff0267606abcbfa03dc5e4c108e7f3d33989952df2f4f1476df8fe53eaa39d2338a87b6ccc91587a67\
+bc0da2f5667248ce969b91f1521c5bfda97c8f062b62d768a9d302f4a4bd0e67646c6666a9fea93749a65d06fdcd0168fe81edac542fc287503a592\
+61591a686b418ac2602e2464f6679ef7ecf5387af45e5fdd72224695e454d6676687b03a5858afe71dda7180a59ef2e1d8c81c4a9c8375e62c43711\
+cbd0e7d437a5913bc4d7e8fbb71f68e4805ad41bd624c06e84761dbda3014c1576a866c073ca32b37007884730ac9f831b95db8ce10f0db45e009d0\
+6e1ad8c96c340c98debee0dd0ca9e6694fe7a69306c15e6a7054cfd612e070f538c6ff0c1a34b257df10087b650da852a5b663a5795a335193dfe64\
+1950ea614ae05b0c202cedabd1ebe6da561e167fe81dd9fc190740a20db38f5356e61f8bed7b3db783a6b53e48f408a8b08f9f79738438a3ed0c4bc\
+f444d5922c76ff03c943a3c72c513047aa75caf51381b5c306fdbaedcd4001a2df456c3afef7559241f553dffac2dfd9ac94570e50c571329203bf0\
+38cbdac9bc76f896635356c402f2f5c105eb4e334f7792716e8e8883352870e949623f29bb8fac428bc858ec3297166afe358e1947b0c2337309315\
+062a040129f978b036657e9323550765cc4c14aaa4c24572eb17a0aa940ba336fd8fd385fb46b5b0c067c59ee42922d2702feb7b43d2ffef11cbdf0\
+1f11c92ac18197a387f0633fd19509b19c0b8a2f63983f6c0a6286593c84d5866ae8d91139b141e8bdf3b7ae7df7d92754186e545f4b600fbe69494\
+3ae4bcef324b9a3f47ba5c835b54a010ca42f3b9cc5368278c148c9b02ea8c4c9f244fd49fa69c9a5feac5376e07f52e64be9c873afca3ebf776fe9\
+fc813bd2e58c6d0dfd951570dbff4b5e73ce547cd100ab320b6944e887d611b3425bfcdf3bfa852ff5804119a1f69e33d624eda6f9e5d1fb2811f9f\
+9f5b3224d009e09621a8fcb524f89c6fcf38f7c933aa027de2b48aa9ddbfa55f56b383f06b8feef09e4709bc4fdcbab659bab4a277a2fbebb98970e\
+44bd68a61b264c695d8ae27a676e123b5fb60c7c4cbc88f24b6554dcfebfde607500f50ec85f589eaa4213ccaa237598660a66009bc56d55455487a\
+28fa24d62e50df57feab0d1c8ec77b1085002d922c52d4a3092f8693c3b9ba9725a4d225637350812b534e93209b414b4516642eca67490199a9217\
+614322972fa2fcc5c7fc2695e9b5762d442e2c7dd8403d14228aa90df58e2ffe1a3c9922f6c5d62649664b63c017fbf3859723e7e97ea6710097683\
+6408a97de3ad7d902c7be0296fb3d476de2460602f65eb7edacc2e4f49b1652fe8948f7afb1cc9f83f3283e6013304160cd2ac7c311c492133252a6\
+5ccf45c5af9c05a47905ac8bfe55f9b912c3fca856abe7863f87392b6f6b0069e3d8412a056b1034aaac506bf2ca51760aa180c5f43a751beb06e88\
+fc6afab4c5dd4aae4a2e6f0293c15278d557c2925acba90c73eeea09ebb95f0d469aa77ae983a0e69dacd55bd8a7e78a41df5227de35af05127fa3b\
+a02f4a3ab98d75992d68a15d393387fe9ef01041569570ad6fe884764e55567311bcacfcffae76554dcfebfde607500f50ec85f589eaade607500f5\
+3ae4bcef324b9a3f47ba5c835b54a010ca42f3b9cc5368278c148c9b02ea8c4c9f244fd49fab'
+}
+
+# Actual length of octet string is 4084 bytes
+update request {
+ Tmp-Integer-0 := "%{length:Tmp-Octets-0}"
+}
+
+if (Tmp-Integer-0 != 4084) {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+# Octets are expanded to 8168 hexits
+if ("%{Tmp-Octets-0}" !~ /^[0-9a-f]{8168}$/) {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+# Octets are expanded to 8168 hexits
+if (Tmp-Octets-0 !~ /^[0-9a-f]{8168}$/) {
+ update reply {
+ Filter-Id += 'fail'
+ }
+}
+
+# We can't do any more until all the xlat code uses dynamically allocated buffers
--- /dev/null
+#
+# PRE: update array
+#
+
+update request {
+ Class := 0x01020304
+ Class += 0x05060708
+ Class += 0x090a0b0c
+}
+
+
+#
+# Use array references in the RHS
+# of the update section
+#
+
+update request {
+ Proxy-State += &Class[0]
+ Proxy-State += &Class[1]
+ Proxy-State += &Class[2]
+}
+
+if (&Proxy-State != 0x01020304) {
+ update reply {
+ Filter-Id := "fail 0"
+ }
+}
+
+# Must be the same as above
+if (&Proxy-State[0] != 0x01020304) {
+ update reply {
+ Filter-Id += "fail 0a"
+ }
+}
+
+if (&Proxy-State[1] != 0x05060708) {
+ update reply {
+ Filter-Id += "fail 1"
+ }
+}
+
+if (&Proxy-State[2] != 0x090a0b0c) {
+ update reply {
+ Filter-Id += "fail 2"
+ }
+}
+
+# must not exist
+if (&Proxy-State[3]) {
+ update reply {
+ Filter-Id += "fail 3"
+ }
+}
+
+#
+# The test passes only if no test above
+# added a Filter-Id
+#
+if (!reply:Filter-Id) {
+ update reply {
+ Filter-Id := "filter"
+ }
+}
\ No newline at end of file
--- /dev/null
+#
+# PRE: update if redundant
+#
+update control {
+ Cleartext-Password := 'hello'
+}
+
+update reply {
+ Filter-Id := "filter"
+}
+
+#
+# Exec with script output to attribute
+#
+update request {
+ Tmp-String-0 = `/bin/sh -c "echo 'foo bar baz'"`
+}
+
+if (Tmp-String-0 != "foo bar baz") {
+ update reply {
+ Filter-Id += "fail 1"
+ }
+}
+
+#
+# Exec with output to list (single attribute)
+#
+update {
+ request: = `/bin/sh -c "echo Tmp-String-0 := foo"`
+}
+
+if (Tmp-String-0 != 'foo') {
+ update reply {
+ Filter-Id += "fail 2"
+ }
+}
+
+#
+# Exec with output to list (multiple attributes)
+#
+update {
+ request: = `/bin/sh -c 'echo Tmp-String-0 := foo, Tmp-String-1 := bar'`
+}
+
+if ((Tmp-String-0 != 'foo') || (Tmp-String-1 != 'bar')) {
+ update reply {
+ Filter-Id += "fail 3"
+ }
+}
+
+#
+# Failed exec (malformed attributes) - check no attributes are added
+#
+update request {
+ Tmp-String-0 !* ANY
+ Tmp-String-1 !* ANY
+}
+
+redundant {
+ group {
+ update {
+ request: = `/bin/sh -c 'echo Tmp-String-0 := foo, Tmp-String-1 ?= bar'`
+ }
+ }
+ ok
+}
+if (Tmp-String-0 || Tmp-String-1) {
+ update reply {
+ Filter-Id += "fail 4"
+ }
+}
+
+#
+# Exec with output to list - error code
+#
+update request {
+ Tmp-String-0 !* ANY
+ Tmp-String-1 !* ANY
+}
+
+redundant {
+ group {
+ update {
+ request: = `/bin/sh -c 'echo Tmp-String-0 := foo; exit 64'`
+ }
+ }
+ ok
+}
+if (Tmp-String-0) {
+ update reply {
+ Filter-Id += "fail 5"
+ }
+}
+
--- /dev/null
+#
+# PRE: update
+#
+# It's an error to update lists that don't exist.
+#
+update {
+ request := reply
+ config += request
+ reply !* ANY
+}
+
+update {
+ reply += `/path/to/foo bar baz`
+}
+
+
+update {
+ request := nope # ERROR
+}
--- /dev/null
+#
+# PRE: update
+#
+update request {
+ NAS-Port := 1000
+}
+
+#
+# Filtering
+#
+update request {
+ NAS-Port == 1000
+}
+
+if (NAS-Port != 1000) {
+ update reply {
+ Filter-Id += "fail 1"
+ }
+}
+
+update request {
+ NAS-Port <= 500
+}
+
+if (NAS-Port != 500) {
+ update reply {
+ Filter-Id += "fail 2"
+ }
+}
+
+update request {
+ NAS-Port >= 2000
+}
+
+if (NAS-Port != 2000) {
+ update reply {
+ Filter-Id += "fail 3"
+ }
+}
+
+# non-existent attribute
+update request {
+ Class -= 0xabcdef
+}
+
+update request {
+ Class -= &Class
+}
+
+update request {
+ NAS-Port -= &NAS-Port
+}
+
+if (!reply:Filter-Id) {
+ update control {
+ Cleartext-Password := 'hello'
+ }
+
+ update reply {
+ Filter-Id := "filter"
+ }
+}
--- /dev/null
+#
+# PRE: update
+#
+# Remove all attributes in a list
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update {
+ request:Tmp-String-0 := 'foobarbaz'
+ request:Tmp-Integer-0 := 123456789
+ request:Tmp-IP-Address-0 := 192.0.2.1
+ request:Tmp-IP-Address-0 += 192.0.2.2
+ control:Tmp-IP-Address-0 := 192.0.2.1
+ control:Tmp-IP-Address-0 += 192.0.2.3
+}
+
+if (("%{Tmp-IP-Address-0[0]}" != 192.0.2.1) || ("%{Tmp-IP-Address-0[1]}" != 192.0.2.2)) {
+ update {
+ reply:Filter-Id := 'fail 1'
+ }
+}
+
+# Remove all attributes in the control list
+update {
+ request:Tmp-IP-Address-0 !* ANY
+}
+
+# Non Tmp-IP-Address-0 address attributes should still be in the request list
+if ((Tmp-String-0 != 'foobarbaz') || (Tmp-Integer-0 != 123456789)) {
+ update reply {
+ reply:Filter-Id += 'fail 2'
+ }
+}
+
+# There should be no Tmp-IP-Address attributes in the request list
+if (Tmp-IP-Address-0 || ("%{Tmp-IP-Address-0[1]}" != '')) {
+ update {
+ reply:Filter-Id += 'fail 3'
+ }
+}
+
+# But there should still be some in the control list
+if ((control:Tmp-IP-Address-0 != 192.0.2.1) || ("%{control:Tmp-IP-Address-0[1]}" != 192.0.2.3)) {
+ update {
+ reply:Filter-Id += 'fail 4'
+ }
+}
--- /dev/null
+#
+# PRE: update update-remove-value
+#
+# Remove all attributes in a list
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update {
+ request:Tmp-String-0 := 'foobarbaz'
+ request:Tmp-Integer-0 := 123456789
+ request:Tmp-IP-Address-0 := 192.0.2.1
+ request:Tmp-IP-Address-0 += 192.0.2.2
+ request:Tmp-IP-Address-0 += 192.0.2.3
+ request:Tmp-IP-Address-0 += 192.0.2.2
+ request:Tmp-IP-Address-0 += 192.0.2.4
+}
+
+
+update request {
+ Tmp-IP-Address-0[3] -= 192.0.2.2
+}
+
+# Only the 1st, 2nd, 3rd and 5th Tmp-IP-Address attributes should still be in the list
+if (("%{Tmp-IP-Address-0[0]}" != '192.0.2.1') || \
+ ("%{Tmp-IP-Address-0[1]}" != '192.0.2.2') || \
+ ("%{Tmp-IP-Address-0[2]}" != '192.0.2.3') || \
+ ("%{Tmp-IP-Address-0[3]}" != '192.0.2.4') || \
+ ("%{Tmp-IP-Address-0[4]}" != '')) {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+# There's still a 192.0.2.2 but it's not at index 3
+update request {
+ Tmp-IP-Address-0[3] -= 192.0.2.2
+}
+
+# Should be the same as the previous result
+if (("%{Tmp-IP-Address-0[0]}" != '192.0.2.1') || \
+ ("%{Tmp-IP-Address-0[1]}" != '192.0.2.2') || \
+ ("%{Tmp-IP-Address-0[2]}" != '192.0.2.3') || \
+ ("%{Tmp-IP-Address-0[3]}" != '192.0.2.4') || \
+ ("%{Tmp-IP-Address-0[4]}" != '')) {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+# Remove whatever's at index 0
+update request {
+ Tmp-IP-Address-0[0] !* ANY
+}
+
+# IP address at index 0 should be removed
+if (("%{Tmp-IP-Address-0[0]}" != '192.0.2.2') || \
+ ("%{Tmp-IP-Address-0[1]}" != '192.0.2.3') || \
+ ("%{Tmp-IP-Address-0[2]}" != '192.0.2.4') || \
+ ("%{Tmp-IP-Address-0[3]}" != '')) {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+# Remove whatever's at index 3 (should be nothing)
+update request {
+ Tmp-IP-Address-0[3] !* ANY
+}
+
+# Should be the same as the previous result
+if (("%{Tmp-IP-Address-0[0]}" != '192.0.2.2') || \
+ ("%{Tmp-IP-Address-0[1]}" != '192.0.2.3') || \
+ ("%{Tmp-IP-Address-0[2]}" != '192.0.2.4') || \
+ ("%{Tmp-IP-Address-0[3]}" != '')) {
+ update reply {
+ Filter-Id += 'fail 4'
+ }
+}
+
+# Remove all instances of Tmp-IP-Address
+update request {
+ Tmp-IP-Address-0 !* ANY
+}
+
+# No more IP address attributes!
+if ("%{Tmp-IP-Address-0[0]}" != '') {
+ update reply {
+ Filter-Id += 'fail 5'
+ }
+}
+
+# Non Tmp-IP-Address-0 address attributes should still be in the request list
+if ((Tmp-String-0 != 'foobarbaz') || (Tmp-Integer-0 != 123456789)) {
+ update reply {
+ Filter-Id += 'fail 6'
+ }
+}
--- /dev/null
+#
+# PRE: update
+#
+# Remove all attributes in a list
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update request {
+ Tmp-String-0 := 'foobarbaz'
+ Tmp-Integer-0 := 123456789
+ Tmp-IP-Address-0 := 192.0.2.1
+}
+
+if ((Tmp-String-0 != 'foobarbaz') || (Tmp-Integer-0 != 123456789) || (Tmp-IP-Address-0 != 192.0.2.1)) {
+ update reply {
+ Filter-Id += 'fail 0'
+ }
+}
+
+# Remove all attributes in the control list
+update {
+ request: !* ANY
+}
+
+# All attributes should now of been removed
+if ((Tmp-String-0 && (Tmp-String-0 == 'foobarbaz')) || \
+ (Tmp-Integer-0 && (Tmp-Integer-0 == 123456789)) || \
+ (Tmp-IP-Address-0 && (Tmp-IP-Address-0 == 192.0.2.1))) {
+ update reply {
+ Filter-Id := 'fail 1'
+ }
+}
+
+# This will of been removed too
+update request {
+ User-Password := 'hello'
+}
--- /dev/null
+#
+# PRE: update update-remove-value update-remove-index update-tag
+#
+# Remove all attributes in a list
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update {
+ request:Tunnel-Server-Endpoint += '192.0.1.1'
+ request:Tunnel-Server-Endpoint += '192.0.1.2'
+ request:Tunnel-Server-Endpoint:1 += '192.0.1.1'
+ request:Tunnel-Server-Endpoint:2 += '192.0.2.1'
+ request:Tunnel-Server-Endpoint:2 += '192.0.2.2'
+ request:Tunnel-Server-Endpoint:3 += '192.0.3.1'
+ request:Tunnel-Server-Endpoint:3 += '192.0.3.2'
+ request:Tunnel-Server-Endpoint:3 += '192.0.3.3'
+ control: += request:
+}
+
+# Check [#] is working correctly (should probably be another set of tests)
+if (("%{request:Tunnel-Server-Endpoint[#]}" != 8) || \
+ ("%{request:Tunnel-Server-Endpoint:0[#]}" != 2) || \
+ ("%{request:Tunnel-Server-Endpoint:1[#]}" != 1) || \
+ ("%{request:Tunnel-Server-Endpoint:2[#]}" != 2) || \
+ ("%{request:Tunnel-Server-Endpoint:3[#]}" != 3)) {
+ update reply {
+ Filter-Id += 'fail 0'
+ }
+}
+
+update {
+ Tunnel-Server-Endpoint !* ANY
+}
+
+# List should now be empty
+if ("%{request:Tunnel-Server-Endpoint[#]}" != 0) {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+# Reset the list
+update {
+ request: += control:
+}
+
+# Now remove all Tunnel-Server-Endpoint attributes with :2
+update {
+ Tunnel-Server-Endpoint:2 !* ANY
+}
+
+if (("%{request:Tunnel-Server-Endpoint[#]}" != 6) || \
+ ("%{request:Tunnel-Server-Endpoint:0[#]}" != 2) || \
+ ("%{request:Tunnel-Server-Endpoint:1[#]}" != 1) || \
+ ("%{request:Tunnel-Server-Endpoint:2[#]}" != 0) || \
+ ("%{request:Tunnel-Server-Endpoint:3[#]}" != 3)) {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+# Now remove all Tunnel-Server-Endpoint attributes with :0 (no tags)
+update {
+ Tunnel-Server-Endpoint:0 !* ANY
+}
+
+if (("%{request:Tunnel-Server-Endpoint[#]}" != 4) || \
+ ("%{request:Tunnel-Server-Endpoint:0[#]}" != 0) || \
+ ("%{request:Tunnel-Server-Endpoint:1[#]}" != 1) || \
+ ("%{request:Tunnel-Server-Endpoint:2[#]}" != 0) || \
+ ("%{request:Tunnel-Server-Endpoint:3[#]}" != 3)) {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+# Now remove all Tunnel-Server-Endpoint attributes with :3
+update {
+ Tunnel-Server-Endpoint:3 !* ANY
+}
+
+if (("%{request:Tunnel-Server-Endpoint[#]}" != 1) || \
+ ("%{request:Tunnel-Server-Endpoint:0[#]}" != 0) || \
+ ("%{request:Tunnel-Server-Endpoint:1[#]}" != 1) || \
+ ("%{request:Tunnel-Server-Endpoint:2[#]}" != 0) || \
+ ("%{request:Tunnel-Server-Endpoint:3[#]}" != 0)) {
+ update reply {
+ Filter-Id += 'fail 4'
+ }
+}
+
+# Now remove all Tunnel-Server-Endpoint attributes with :1
+update {
+ Tunnel-Server-Endpoint:1 !* ANY
+}
+
+if (("%{request:Tunnel-Server-Endpoint[#]}" != 0) || \
+ ("%{request:Tunnel-Server-Endpoint:0[#]}" != 0) || \
+ ("%{request:Tunnel-Server-Endpoint:1[#]}" != 0) || \
+ ("%{request:Tunnel-Server-Endpoint:2[#]}" != 0) || \
+ ("%{request:Tunnel-Server-Endpoint:3[#]}" != 0)) {
+ update reply {
+ Filter-Id += 'fail 5'
+ }
+}
+
+# Reset the list
+update {
+ request: += control:
+}
+
+# Remove all Tunnel-Server-Endpoint attributes at :3[0] (none)
+update {
+ Tunnel-Server-Endpoint:1[3] !* ANY
+}
+
+if (Tunnel-Server-Endpoint:3[0] != '192.0.3.1') {
+ update reply {
+ Filter-Id += 'fail 6'
+ }
+}
+
+if (Tunnel-Server-Endpoint:3[1] != '192.0.3.2') {
+ update reply {
+ Filter-Id += 'fail 7'
+ }
+}
+
+if (Tunnel-Server-Endpoint:3[2] != '192.0.3.3') {
+ update reply {
+ Filter-Id += 'fail 8'
+ }
+}
+
+# Remove all Tunnel-Server-Endpoint attributes at :3[1]
+update {
+ Tunnel-Server-Endpoint:3[1] !* ANY
+}
+
+if (Tunnel-Server-Endpoint:3[0] != '192.0.3.1') {
+ update reply {
+ Filter-Id += 'fail 9'
+ }
+}
+
+if (Tunnel-Server-Endpoint:3[1] != '192.0.3.3') {
+ update reply {
+ Filter-Id += 'fail 10'
+ }
+}
+
+# Remove any Tunnel-Server-Endpoint with a value of '192.0.1.1' (should remove both tagged and untagged versions)
+update {
+ Tunnel-Server-Endpoint -= '192.0.1.1'
+}
+
+# Also checks whether presence checks for tagged attributes work correctly
+if (request:Tunnel-Server-Endpoint:1) {
+ update reply {
+ Filter-Id += 'fail 11'
+ }
+}
+
+if (request:Tunnel-Server-Endpoint:0[0] != '192.0.1.2') {
+ update reply {
+ Filter-Id += 'fail 12'
+ }
+}
+
+# Remove any Tunnel-Server-Endpoint with a value of '192.0.3.1'
+update {
+ Tunnel-Server-Endpoint:3 -= '192.0.3.2'
+}
+
+if (request:Tunnel-Server-Endpoint:3[0] != '192.0.3.1') {
+ update reply {
+ Filter-Id += 'fail 13'
+ }
+}
+
+if (request:Tunnel-Server-Endpoint:3[1] != '192.0.3.3') {
+ update reply {
+ Filter-Id += 'fail 14'
+ }
+}
+
+# Reset the list
+update {
+ request: !* ANY
+}
+update {
+ request: += control:
+}
+
+# Remove only the tagged version of '192.0.1.1'
+update {
+ request:Tunnel-Server-Endpoint:1 -= '192.0.1.1'
+}
+
+if (request:Tunnel-Server-Endpoint:0[0] != '192.0.1.1') {
+ update reply {
+ Filter-Id += 'fail 15'
+ }
+}
+
+# Reset the list
+update {
+ request: !* ANY
+}
+update {
+ request: += control:
+}
+
+# Remove only the untagged version of '192.0.1.1'
+update {
+ request:Tunnel-Server-Endpoint:0 -= '192.0.1.1'
+}
+
+if (request:Tunnel-Server-Endpoint:1[0] != '192.0.1.1') {
+ update reply {
+ Filter-Id += 'fail 16'
+ }
+}
+
+# Remove the value of Tunnel-Server-Endpoint:3 at index 1 only if it matches '192.0.3.3' (which it does)
+update {
+ Tunnel-Server-Endpoint:3[1] -= '192.0.3.2'
+}
+
+if (Tunnel-Server-Endpoint:3[0] != '192.0.3.1') {
+ update reply {
+ Filter-Id += 'fail 17'
+ }
+}
+
+if (Tunnel-Server-Endpoint:3[1] != '192.0.3.3') {
+ update reply {
+ Filter-Id += 'fail 18'
+ }
+}
+
+# Reset the list
+update {
+ request: !* ANY
+}
+update {
+ request: += control:
+}
+
+# Remove the value of Tunnel-Server-Endpoint:3 at index 1 only if it matches '192.0.3.4' (which it doesn't)
+update {
+ Tunnel-Server-Endpoint:3[1] -= '192.0.3.4'
+}
+
+if (Tunnel-Server-Endpoint:3[0] != '192.0.3.1') {
+ update reply {
+ Filter-Id += 'fail 19'
+ }
+}
+
+if (Tunnel-Server-Endpoint:3[1] != '192.0.3.2') {
+ update reply {
+ Filter-Id += 'fail 20'
+ }
+}
+
+if (Tunnel-Server-Endpoint:3[2] != '192.0.3.3') {
+ update reply {
+ Filter-Id += 'fail 21'
+ }
+}
+
--- /dev/null
+#
+# PRE: update
+#
+# Remove all attributes in a list
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update {
+ request:Tmp-String-0 := 'foobarbaz'
+ request:Tmp-Integer-0 := 123456789
+ request:Tmp-IP-Address-0 := 192.0.2.1
+ request:Tmp-IP-Address-0 += 192.0.2.2
+ request:Tmp-IP-Address-0 += 192.0.2.3
+ request:Tmp-IP-Address-0 += 192.0.2.4
+ control:Tmp-IP-Address-0 := 192.0.2.1
+ control:Tmp-IP-Address-0 += 192.0.2.3
+}
+
+if (("%{Tmp-IP-Address-0[0]}" != 192.0.2.1) || \
+ ("%{Tmp-IP-Address-0[1]}" != 192.0.2.2) || \
+ ("%{Tmp-IP-Address-0[2]}" != 192.0.2.3) || \
+ ("%{Tmp-IP-Address-0[3]}" != 192.0.2.4)) {
+ update reply {
+ Filter-Id += 'fail 0'
+ }
+}
+
+# Remove Tmp-IP-Address-0 with a specific value
+update {
+ request:Tmp-IP-Address-0 -= 192.0.2.1
+}
+
+# Only the 2nd, 3rd and 4th Tmp-IP-Address attributes should still be in the list
+if (("%{Tmp-IP-Address-0[0]}" != '192.0.2.2') || \
+ ("%{Tmp-IP-Address-0[1]}" != '192.0.2.3') || \
+ ("%{Tmp-IP-Address-0[2]}" != '192.0.2.4') || \
+ ("%{Tmp-IP-Address-0[3]}" != '')) {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+# Remove Tmp-IP-Address-0 with a specific value (somewhere in the middle)
+update {
+ request:Tmp-IP-Address-0 -= 192.0.2.3
+}
+
+# Only the 1st, and 3rd Tmp-IP-Address attributes should still be in the list
+if (("%{Tmp-IP-Address-0[0]}" != '192.0.2.2') || \
+ ("%{Tmp-IP-Address-0[1]}" != '192.0.2.4') || \
+ ("%{Tmp-IP-Address-0[2]}" != '')) {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+# Remove Tmp-IP-Address-0 with a specific value (which doesn't exist)
+update {
+ request:Tmp-IP-Address-0 -= 192.0.2.3
+}
+
+# Only the 1st, and 3rd Tmp-IP-Address attributes should still be in the list
+if (("%{Tmp-IP-Address-0[0]}" != '192.0.2.2') || \
+ ("%{Tmp-IP-Address-0[1]}" != '192.0.2.4') || \
+ ("%{Tmp-IP-Address-0[2]}" != '')) {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+# Remove Tmp-IP-Address-4 (which doesn't exist - more to check for SEGV/assert)
+update {
+ request:Tmp-IP-Address-4 -= 192.0.2.3
+}
+
+# Remove Tmp-IP-Address-0 with a specific value
+update {
+ request:Tmp-IP-Address-0 -= 192.0.2.4
+}
+
+# Only the 1st, and 3rd Tmp-IP-Address attributes should still be in the list
+if (("%{Tmp-IP-Address-0[0]}" != '192.0.2.2') || \
+ ("%{Tmp-IP-Address-0[1]}" != '')) {
+ update reply {
+ Filter-Id += 'fail 4'
+ }
+}
+
+# Remove Tmp-IP-Address-0 with a specific value
+update {
+ request:Tmp-IP-Address-0 -= 192.0.2.2
+}
+
+# Only the 1st, and 3rd Tmp-IP-Address attributes should still be in the list
+if ("%{Tmp-IP-Address-0[0]}" != '') {
+ update reply {
+ Filter-Id += 'fail 5'
+ }
+}
+
+# Non Tmp-IP-Address-0 address attributes should still be in the request list
+if ((Tmp-String-0 != 'foobarbaz') || (Tmp-Integer-0 != 123456789)) {
+ update reply {
+ Filter-Id += 'fail 6'
+ }
+}
+
+# But there should still be some in the control list
+if (("%{control:Tmp-IP-Address-0[0]}" != 192.0.2.1) || ("%{control:Tmp-IP-Address-0[1]}" != 192.0.2.3)) {
+ update {
+ Filter-Id += 'fail 7'
+ }
+}
--- /dev/null
+#
+# PRE: update
+#
+# Remove all attributes in a list
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update request {
+ Tunnel-Server-Endpoint:0 := '192.0.1.1' # Should not be tagged
+ Tunnel-Server-Endpoint:0 += '192.0.1.2' # Should not be tagged
+ Tunnel-Server-Endpoint:1 := '192.0.2.1'
+ Tunnel-Server-Endpoint:1 += '192.0.2.2'
+ Tunnel-Server-Endpoint:2 := '192.0.3.1'
+ Tunnel-Server-Endpoint:2 += '192.0.3.2'
+}
+
+update request {
+ Tmp-Integer-0 := "%{debug_attr:request:}"
+}
+
+
+#
+# Selecting on attributes which have no tag (0)
+#
+if (Tunnel-Server-Endpoint:0[0] != '192.0.1.1') {
+ update {
+ reply:Filter-Id += 'fail 1'
+ }
+}
+
+if (Tunnel-Server-Endpoint:0[1] != '192.0.1.2') {
+ update {
+ reply:Filter-Id += 'fail 2'
+ }
+}
+
+#
+# Selecting on attributes with no tag specified (should match all of that type)
+#
+if (Tunnel-Server-Endpoint[0] != '192.0.1.1') {
+ update {
+ reply:Filter-Id += 'fail 3'
+ }
+}
+
+if (Tunnel-Server-Endpoint[1] != '192.0.1.2') {
+ update {
+ reply:Filter-Id += 'fail 4'
+ }
+}
+
+if (Tunnel-Server-Endpoint[2] != '192.0.2.1') {
+ update {
+ reply:Filter-Id += 'fail 5'
+ }
+}
+
+#
+# Now the none xlat version
+#
+# Check that access attributes by tag works first
+if (Tunnel-Server-Endpoint:2 != '192.0.3.1') {
+ update {
+ reply:Filter-Id += 'fail 6'
+ }
+}
+
+if (Tunnel-Server-Endpoint:2 == '192.0.3.2') {
+ update {
+ reply:Filter-Id += 'fail 7'
+ }
+}
+
+if (Tunnel-Server-Endpoint:1 != '192.0.2.1') {
+ update {
+ reply:Filter-Id += 'fail 8'
+ }
+}
+
+# Get the first instance of Tunnel-Server-Endpoint:2
+if (Tunnel-Server-Endpoint:2[0] != '192.0.3.1') {
+ update {
+ reply:Filter-Id += 'fail 9'
+ }
+}
+
+# Get the first instance of Tunnel-Server-Endpoint:2
+if (Tunnel-Server-Endpoint:2[1] != '192.0.3.2') {
+ update {
+ reply:Filter-Id += 'fail 10'
+ }
+}
+
+#
+# Assignment (bare)
+#
+update request {
+ Tmp-String-1 += &Tunnel-Server-Endpoint:2 # 0
+ Tmp-String-1 += &Tunnel-Server-Endpoint:2 # 1
+ Tmp-String-1 += &Tunnel-Server-Endpoint:1 # 2
+ Tmp-String-1 += &Tunnel-Server-Endpoint:2[0] # 3
+ Tmp-String-1 += &Tunnel-Server-Endpoint:2[1] # 4
+ Tmp-String-1 += &Tunnel-Server-Endpoint:0[0] # 5
+ Tmp-String-1 += &Tunnel-Server-Endpoint:0[1] # 6
+ Tmp-String-1 += &Tunnel-Server-Endpoint:0[2] # 7 (No attribute should be added here)
+ Tmp-String-1 += &Tunnel-Server-Endpoint[0] # 8
+ Tmp-String-1 += &Tunnel-Server-Endpoint[1] # 9
+ Tmp-String-1 += &Tunnel-Server-Endpoint[2] # 10
+}
+
+# Check that access attributes by tag works first
+if (Tmp-String-1[0] != '192.0.3.1') {
+ update {
+ reply:Filter-Id += 'fail 11'
+ }
+}
+
+if (Tmp-String-1[1] == '192.0.3.2') {
+ update {
+ reply:Filter-Id += 'fail 12'
+ }
+}
+
+if (Tmp-String-1[2] != '192.0.2.1') {
+ update {
+ reply:Filter-Id += 'fail 13'
+ }
+}
+
+# Get the first instance of Tunnel-Server-Endpoint:2
+if (Tmp-String-1[3] != '192.0.3.1') {
+ update {
+ reply:Filter-Id += 'fail 14'
+ }
+}
+
+# Get the first instance of Tunnel-Server-Endpoint:2
+if (Tmp-String-1[4] != '192.0.3.2') {
+ update {
+ reply:Filter-Id += 'fail 15'
+ }
+}
+
+# Now check the assignment
+if (Tmp-String-1[5] != '192.0.1.1') {
+ update {
+ reply:Filter-Id += 'fail 16'
+ }
+}
+
+if (Tmp-String-1[6] != '192.0.1.2') {
+ update {
+ reply:Filter-Id += 'fail 17'
+ }
+}
+
+if (Tmp-String-1[7] != '192.0.1.1') {
+ update {
+ reply:Filter-Id += 'fail 19'
+ }
+}
+
+if (Tmp-String-1[8] != '192.0.1.2') {
+ update {
+ reply:Filter-Id += 'fail 20'
+ }
+}
+
+if (Tmp-String-1[9] != '192.0.2.1') {
+ update {
+ reply:Filter-Id += 'fail 21'
+ }
+}
--- /dev/null
+#
+# PRE: update
+#
+# Remove all attributes in a list
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update request {
+ Tmp-IP-Address-0 := 192.0.2.1
+ Tmp-IP-Address-0 += 192.0.2.2
+}
+
+if ("%{Tmp-IP-Address-0[#]}" != 2) {
+ update {
+ reply:Filter-Id := 'fail'
+ }
+}
+
+if (("%{Tmp-IP-Address-0[0]}" != 192.0.2.1) || ("%{Tmp-IP-Address-0[1]}" != 192.0.2.2)) {
+ update {
+ reply:Filter-Id := 'fail'
+ }
+}
+
+if ("%{Tmp-IP-Address-0[*]}" != '192.0.2.1,192.0.2.2') {
+ update {
+ reply:Filter-Id := 'fail'
+ }
+}
+
+# Try calling these xlats in mapping too, they may get optimised to VPTs which is a
+# different code path.
+update request {
+ Tmp-IP-Address-1 += "%{Tmp-IP-Address-0[1]}"
+ Tmp-IP-Address-1 += "%{Tmp-IP-Address-0[0]}"
+ Tmp-String-0 = "%{Tmp-IP-Address-0[*]}"
+ Tmp-Integer-0 = "%{Tmp-IP-Address-0[#]}"
+}
+
+if (Tmp-IP-Address-1[0] != 192.0.2.2) {
+ update {
+ reply:Filter-Id += 'fail 3'
+ }
+}
+
+if (Tmp-IP-Address-1[1] != 192.0.2.1) {
+ update {
+ reply:Filter-Id += 'fail 4'
+ }
+}
+
+if (Tmp-String-0 != '192.0.2.1,192.0.2.2') {
+ update {
+ reply:Filter-Id += 'fail 5'
+ }
+}
+
+if (Tmp-Integer-0 != 2) {
+ update {
+ reply:Filter-Id += 'fail 6'
+ }
+}
+
+
--- /dev/null
+#
+# PRE: update
+#
+# Remove all attributes in a list
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update request {
+ Tunnel-Server-Endpoint := '192.0.1.1' # Should not be tagged
+ Tunnel-Server-Endpoint:0 += '192.0.1.2' # Should not be tagged
+ Tunnel-Server-Endpoint:1 := '192.0.2.1'
+ Tunnel-Server-Endpoint:1 += '192.0.2.2'
+ Tunnel-Server-Endpoint:2 := '192.0.3.1'
+ Tunnel-Server-Endpoint:2 += '192.0.3.2'
+}
+
+update request {
+ Tmp-Integer-0 := "%{debug_attr:request:}"
+}
+
+# Check the tag printing xlat works correctly
+if ("%{tag:Tunnel-Server-Endpoint[0]}" != '') {
+ update {
+ reply:Filter-Id += 'fail 0a'
+ }
+}
+
+if ("%{tag:Tunnel-Server-Endpoint[1]}" != '') {
+ update {
+ reply:Filter-Id += 'fail 0b'
+ }
+}
+
+
+if ("%{tag:Tunnel-Server-Endpoint[2]}" != '1') {
+ update {
+ reply:Filter-Id += 'fail 0c'
+ }
+}
+
+if ("%{tag:Tunnel-Server-Endpoint[5]}" != '2') {
+ update {
+ reply:Filter-Id += 'fail 0d'
+ }
+}
+
+if ("%{tag:Tunnel-Server-Endpoint[6]}" != '') {
+ update {
+ reply:Filter-Id += 'fail 0e'
+ }
+}
+
+if ("%{tag:control:Cleartext-Password}" != '') {
+ update {
+ reply:Filter-Id += 'fail 0f'
+ }
+}
+
+# Check that access attributes by tag works first
+if ("%{Tunnel-Server-Endpoint:2}" != '192.0.3.1') {
+ update {
+ reply:Filter-Id += 'fail 1'
+ }
+}
+
+if ("%{Tunnel-Server-Endpoint:2}" == '192.0.3.2') {
+ update {
+ reply:Filter-Id += 'fail 2'
+ }
+}
+
+if ("%{Tunnel-Server-Endpoint:1}" != '192.0.2.1') {
+ update {
+ reply:Filter-Id += 'fail 3'
+ }
+}
+
+# Get the first instance of Tunnel-Server-Endpoint:2
+if ("%{Tunnel-Server-Endpoint:2[0]}" != '192.0.3.1') {
+ update {
+ reply:Filter-Id += 'fail 4'
+ }
+}
+
+# Get the first instance of Tunnel-Server-Endpoint:2
+if ("%{Tunnel-Server-Endpoint:2[1]}" != '192.0.3.2') {
+ update {
+ reply:Filter-Id += 'fail 5'
+ }
+}
+
+if ("%{Tunnel-Server-Endpoint:0[2]}" != '') {
+ update {
+ reply:Filter-Id += 'fail 6'
+ }
+}
+
+if ("%{Tunnel-Server-Endpoint:0[0]}" != '192.0.1.1') {
+ update {
+ reply:Filter-Id += 'fail 7'
+ }
+}
+
+if ("%{Tunnel-Server-Endpoint:0[1]}" != '192.0.1.2') {
+ update {
+ reply:Filter-Id += 'fail 8'
+ }
+}
+
+if ("%{Tunnel-Server-Endpoint:0[2]}" != '') {
+ update {
+ reply:Filter-Id += 'fail 9'
+ }
+}
+
+#
+# Selecting on attributes with no tag specified (should match all of that type)
+#
+if ("%{Tunnel-Server-Endpoint[0]}" != '192.0.1.1') {
+ update {
+ reply:Filter-Id += 'fail 10'
+ }
+}
+
+if ("%{Tunnel-Server-Endpoint[1]}" != '192.0.1.2') {
+ update {
+ reply:Filter-Id += 'fail 11'
+ }
+}
+
+if ("%{Tunnel-Server-Endpoint[2]}" != '192.0.2.1') {
+ update {
+ reply:Filter-Id += 'fail 12'
+ }
+}
+
+#
+# Assignment (xlat)
+#
+update request {
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint:2}" #0
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint:2}" #1
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint:1}" #2
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint:2[0]}" #3
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint:2[1]}" #4
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint:0[0]}" #5
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint:0[1]}" #6
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint:0[2]}" #7
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint[0]}" #8
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint[1]}" #9
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint[2]}" #10
+}
+
+# Check that access attributes by tag works first
+if (Tmp-String-0[0] != '192.0.3.1') {
+ update {
+ reply:Filter-Id += 'fail 13'
+ }
+}
+
+if (Tmp-String-0[1] == '192.0.3.2') {
+ update {
+ reply:Filter-Id += 'fail 14'
+ }
+}
+
+if (Tmp-String-0[2] != '192.0.2.1') {
+ update {
+ reply:Filter-Id += 'fail 15'
+ }
+}
+
+# Get the first instance of Tunnel-Server-Endpoint:2
+if (Tmp-String-0[3] != '192.0.3.1') {
+ update {
+ reply:Filter-Id += 'fail 16'
+ }
+}
+
+# Get the first instance of Tunnel-Server-Endpoint:2
+if (Tmp-String-0[4] != '192.0.3.2') {
+ update {
+ reply:Filter-Id += 'fail 17'
+ }
+}
+
+# Now check the assignment
+if (Tmp-String-0[5] != '192.0.1.1') {
+ update {
+ reply:Filter-Id += 'fail 18'
+ }
+}
+
+if (Tmp-String-0[6] != '192.0.1.2') {
+ update {
+ reply:Filter-Id += 'fail 19'
+ }
+}
+
+if (Tmp-String-0[7] != '') {
+ update {
+ reply:Filter-Id += 'fail 20'
+ }
+}
+
+if (Tmp-String-0[8] != '192.0.1.1') {
+ update {
+ reply:Filter-Id += 'fail 21'
+ }
+}
+
+if (Tmp-String-0[9] != '192.0.1.2') {
+ update {
+ reply:Filter-Id += 'fail 22'
+ }
+}
+
+if (Tmp-String-0[10] != '192.0.2.1') {
+ update {
+ reply:Filter-Id += 'fail 23'
+ }
+}
--- /dev/null
+#
+# PRE: update if
+#
+# Remove all attributes in a list
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+#
+# Regression test for 0x prefix. xlat expanded
+# octet strings must NOT have a 0x prefix added
+#
+update request {
+ Tmp-Octets-0 := 0x0001020304050607
+ Tmp-Octets-0 += 0x0706050403020100
+}
+
+if ("%{Tmp-Octets-0}" != '0001020304050607') {
+ update {
+ reply:Filter-Id := 'fail 1'
+ }
+}
+
+if ("%{Tmp-Octets-0[0]}" != '0001020304050607') {
+ update {
+ reply:Filter-Id += 'fail 2'
+ }
+}
+
+if ("%{Tmp-Octets-0[*]}" != '0001020304050607,0706050403020100') {
+ update {
+ reply:Filter-Id += 'fail 3'
+ }
+}
--- /dev/null
+#
+# PRE: if
+#
+
+update reply {
+ Filter-Id := "filter"
+}
+
+if ("%{Client-Shortname}" != '<UNKNOWN-CLIENT>') {
+ update reply {
+ Filter-Id += "fail 0"
+ }
+}
+
+if ("%{Request-Processing-Stage}" != 'authorize') {
+ update reply {
+ Filter-Id += "fail 1"
+ }
+}
+
+if ("%{Virtual-Server}" != 'default') {
+ update reply {
+ Filter-Id += "fail 2"
+ }
+}
+
+if ("%{Module-Return-Code}" != '') {
+ update reply {
+ Filter-Id += "fail 3a"
+ }
+}
+
+ok
+if ("%{Module-Return-Code}" != 'ok') {
+ update reply {
+ Filter-Id += "fail 3b"
+ }
+}
+
+if ("%{Packet-Type}" != 'Access-Request') {
+ update reply {
+ Filter-Id += "fail 4"
+ }
+}
+
+# Response hasn't been set yet
+if ("%{Response-Packet-Type}" != '') {
+ update reply {
+ Filter-Id += "fail 5"
+ }
+}
+
+if ("%{Packet-Authentication-Vector}" != '00000000000000000000000000000000') {
+ update reply {
+ Filter-Id += "fail 6"
+ }
+}
+
+if ("%{Client-IP-Address}" != 127.0.0.1) {
+ update reply {
+ Filter-Id += "fail 7a"
+ }
+}
+
+if ("%{Packet-Src-IP-Address}" != 127.0.0.1) {
+ update reply {
+ Filter-Id += "fail 7b"
+ }
+}
+
+if ("%{Packet-Dst-IP-Address}" != 127.0.0.1) {
+ update reply {
+ Filter-Id += "fail 8"
+ }
+}
+
+# Can't have both...
+if ("%{Packet-Src-IPv6-Address}" != '') {
+ update reply {
+ Filter-Id += "fail 9"
+ }
+}
+
+if ("%{Packet-Dst-IPv6-Address}" != '') {
+ update reply {
+ Filter-Id += "fail 10"
+ }
+}
+
+if ("%{Packet-Src-Port}" != '18120') {
+ update reply {
+ Filter-Id += "fail 11"
+ }
+}
+
+if ("%{Packet-Dst-Port}" != '1812') {
+ update reply {
+ Filter-Id += "fail 12"
+ }
+}
+
+
+# We should allow the user to overload virtual attributes
+update request {
+ Client-Shortname := 'my_test_client'
+}
+
+if ("%{Client-Shortname}" != 'my_test_client') {
+ update reply {
+ Filter-Id += "fail 13"
+ }
+}
+
+# Operations on virtual attributes should be the same as on real ones
+if ("%{Virtual-Server[0]}" != 'default') {
+ update reply {
+ Filter-Id += "fail 14"
+ }
+}
+
+if ("%{Virtual-Server[*]}" != 'default') {
+ update reply {
+ Filter-Id += "fail 15"
+ }
+}
+
+if ("%{Virtual-Server[#]}" != 1) {
+ update reply {
+ Filter-Id += "fail 16"
+ }
+}
--- /dev/null
+info locals
+info args
+thread apply all bt full
+quit
# ./eapol_test -c peap-mschapv2.conf -s testing123
#
network={
- ssid="example"
- key_mgmt=WPA-EAP
- eap=PEAP
- identity="bob"
- anonymous_identity="anonymous"
- password="bob"
- phase2="auth=MSCHAPV2"
+ ssid="example"
+ key_mgmt=WPA-EAP
+ eap=PEAP
+ identity="bob"
+ anonymous_identity="anonymous"
+ password="bob"
+ phase2="auth=MSCHAPV2"
phase1="peapver=0"
}
* This needs to be kept in lockstep with rbtree.c
*/
-/* red-black tree description */
-typedef enum { Black, Red } NodeColor;
+/* RED-BLACK tree description */
+typedef enum {
+ BLACK,
+ RED
+} node_colour_t;
struct rbnode_t {
- rbnode_t *Left; /* left child */
- rbnode_t *Right; /* right child */
- rbnode_t *Parent; /* parent */
- NodeColor Color; /* node color (black, red) */
- void *Data; /* data stored in node */
+ rbnode_t *left; //!< left child
+ rbnode_t *right; //!< right child
+ rbnode_t *parent; //!< Parent
+ node_colour_t colour; //!< Node colour (BLACK, RED)
+ void *data; //!< data stored in node
};
struct rbtree_t {
#ifndef NDEBUG
- uint32_t magic;
+ uint32_t magic;
#endif
- rbnode_t *Root;
- int num_elements;
- int (*Compare)(void const *, void const *);
- int replace_flag;
- void (*freeNode)(void *);
+ rbnode_t *root;
+ int num_elements;
+ rb_comparator_t compare;
+ rb_free_t free;
+ bool replace;
#ifdef HAVE_PTHREAD_H
- int lock;
- pthread_mutex_t mutex;
+ bool lock;
+ pthread_mutex_t mutex;
#endif
};
-
+#define RBTREE_MAGIC (0x5ad09c42)
/* Storage for the NIL pointer. */
rbnode_t *NIL;
static int r = 0;
static int rvals[MAXSIZE];
-static int store_cb(UNUSED void *ctx, void *i)
+static int store_cb(UNUSED void *ctx, void *i)
{
- rvals[r++] = *(int *)i;
+ rvals[r++] = *(int const *)i;
return 0;
}
}
/*
- * Returns the count of black nodes from root to child leaves, or a
- * negative number indicating which red-black rule was broken.
+ * Returns the count of BLACK nodes from root to child leaves, or a
+ * negative number indicating which RED-BLACK rule was broken.
*/
static int rbcount(rbtree_t *t)
{
int count, count_expect;
count_expect = -1;
- n = t->Root;
+ n = t->root;
if (!n || n == NIL) {
return 0;
}
- if (n->Color != Black) {
- return -2; /* Root not Black */
+ if (n->colour != BLACK) {
+ return -2; /* root not BLACK */
}
count = 0;
descend:
- while (n->Left != NIL) {
- if (n->Color == Red) {
- if (n->Left->Color != Black || n->Right->Color != Black) {
- return -4; /* Children of Red nodes must be Black */
+ while (n->left != NIL) {
+ if (n->colour == RED) {
+ if (n->left->colour != BLACK || n->right->colour != BLACK) {
+ return -4; /* Children of RED nodes must be BLACK */
}
}
else {
count++;
}
- n = n->Left;
+ n = n->left;
}
- if (n->Right != NIL) {
- if (n->Color == Red) {
- if (n->Left->Color != Black || n->Right->Color != Black) {
- return -4; /* Children of Red nodes must be Black */
+ if (n->right != NIL) {
+ if (n->colour == RED) {
+ if (n->left->colour != BLACK || n->right->colour != BLACK) {
+ return -4; /* Children of RED nodes must be BLACK */
}
}
else {
count++;
}
- n = n->Right;
+ n = n->right;
}
- if (n->Left != NIL || n->Right != NIL) {
+ if (n->left != NIL || n->right != NIL) {
goto descend;
}
if (count_expect < 0) {
- count_expect = count + (n->Color == Black);
+ count_expect = count + (n->colour == BLACK);
}
else {
- if (count_expect != count + (n->Color == Black)) {
+ if (count_expect != count + (n->colour == BLACK)) {
fprintf(stderr,"Expected %i got %i\n", count_expect, count);
- return -5; /* All paths must traverse the same number of Black nodes. */
+ return -5; /* All paths must traverse the same number of BLACK nodes. */
}
}
ascend:
- if (!n->Parent) return count_expect;
- while (n->Parent->Right == n) {
- n = n->Parent;
- if (!n->Parent) return count_expect;
- if (n->Color == Black) {
+ if (!n->parent) return count_expect;
+ while (n->parent->right == n) {
+ n = n->parent;
+ if (!n->parent) return count_expect;
+ if (n->colour == BLACK) {
count--;
}
}
- if (n->Parent->Left == n) {
- if (n->Parent->Right != NIL) {
- n = n->Parent->Right;
+ if (n->parent->left == n) {
+ if (n->parent->right != NIL) {
+ n = n->parent->right;
goto descend;
}
- n = n->Parent;
- if (!n->Parent) return count_expect;
- if (n->Color == Black) {
+ n = n->parent;
+ if (!n->parent) return count_expect;
+ if (n->colour == BLACK) {
count--;
}
}
t = rbtree_create(comp, free, RBTREE_FLAG_LOCK);
/* Find out the value of the NIL node */
- NIL = t->Root->Left;
+ NIL = t->root->left;
for (i = 0; i < n; i++) {
int *p;
*
*/
- rbtree_walk(t, DeleteOrder, filter_cb, &thresh);
+ rbtree_walk(t, RBTREE_DELETE_ORDER, filter_cb, &thresh);
i = rbcount(t);
fprintf(stderr,"After delete rbcount is %i.\n", i);
if (i < 0) { return i; }
r = 0;
- rbtree_walk(t, InOrder, &store_cb, NULL);
+ rbtree_walk(t, RBTREE_IN_ORDER, &store_cb, NULL);
for (j = i = 0; i < n; i++) {
if (i && vals[i-1] == vals[i]) continue;
rm -f verbose.log
RCODE=0
-rm -rf .cache
-mkdir .cache
-
-#
-# Bootstrap the tests
-#
+echo "Running tests:"
for NAME in $@
do
TOTAL=`grep TESTS $NAME | sed 's/.*TESTS//'`
echo "Test-Name = \"$BASE\"," >> .request
echo 'Test-Number = ' $NUMBER >> .request
- mv .request .cache/$BASE:$NUMBER
- done
-done
-
-echo "Running tests..."
-
-(cd .cache;ls -1 > ../.foo)
-rm -f .bar
-for x in `cat .foo`
-do
- echo "-f .cache/$x" >> .bar
-done
-
-$BIN_PATH/radclient `cat .bar` -xFd . 127.0.0.1:$PORT auth $SECRET > radclient.log 2>&1
-if [ "$?" != "0" ]; then
- echo "Failed running $BIN_PATH/radclient"
- exit 1
-fi
-
-for x in `cat .foo`
-do
- RESULT=`egrep ^\\.cache/$x radclient.log | sed 's/.* //'`
- if [ "$RESULT" = "2" ]; then
- echo "$x : Success"
+ rm ./radclient.log > /dev/null 2>&1
+ $BIN_PATH/radclient -f .request -xF -D ./ 127.0.0.1:$PORT auth $SECRET 1> ./radclient.log
+ if [ "$?" = "0" ]; then
+ echo "${BASE}_${NUMBER} : Success"
else
- echo "$x : FAILED"
+ echo "${BASE}_${NUMBER} : FAILED"
+ cat ./radclient.log
RCODE=1
- fi
+ fi
+ done
done
if [ "$RCODE" = "0" ]
then
- rm -f radiusd.log radclient.log
+ rm -f radiusd.log radclient.log
echo "All tests succeeded"
else
echo "See radclient.log for more details"
#
$(BUILD_DIR)/tests/unit/%: $(DIR)/% $(TESTBINDIR)/radattr | $(BUILD_DIR)/tests/unit
@echo UNIT-TEST $(notdir $@)
- @$(TESTBIN)/radattr -d $(top_srcdir)/share $<
+ @$(TESTBIN)/radattr -D $(top_srcdir)/share $<
@touch $@
#
# $Id$
#
-condition a == b
-data a == b
-
-condition a == b || c == d
-data a == b || c == d
-
#
# A bunch of errors, in the order that the error strings
# appear in parser.c
condition (|| b)
data ERROR offset 1 Empty string is invalid
-condition ((a || b) foo)
-data ERROR offset 10 Unexpected text after condition
+condition ((ok || handled) foo)
+data ERROR offset 17 Unexpected text after condition
# escapes in names are illegal
-condition (a\ foo || b)
-data ERROR offset 2 Unexpected escape
+condition (ok\ foo || handled)
+data ERROR offset 3 Unexpected escape
-condition (a FOO b)
-data ERROR offset 3 Invalid text. Expected comparison operator
+condition (ok FOO handled)
+data ERROR offset 4 Invalid text. Expected comparison operator
-condition (a !x b)
-data ERROR offset 3 Invalid operator
+condition (ok !x handled)
+data ERROR offset 4 Invalid operator
-condition (a =x b)
-data ERROR offset 3 Invalid operator
+condition (ok =x handled)
+data ERROR offset 4 Invalid operator
-condition (a =~ b)
-data ERROR offset 6 Expected regular expression
+condition (ok =~ handled)
+data ERROR offset 7 Expected regular expression
-condition (a == /b/)
-data ERROR offset 6 Unexpected regular expression
+condition (ok == /foo/)
+data ERROR offset 7 Unexpected regular expression
-condition (a == b"foo")
-data ERROR offset 7 Unexpected start of string
+condition (ok == handled"foo")
+data ERROR offset 14 Unexpected start of string
# And now we have a bunch of VALID conditions we want to parse.
# sillyness is OK
-condition ((((((a))))))
-data a
+condition ((((((ok))))))
+data ok
-condition (a == b)
-data a == b
+#
+# Extra braces get squashed
+#
+condition (&User-Name == &User-Password)
+data &User-Name == &User-Password
-condition (!a)
-data !a
+condition (!ok)
+data !ok
-condition !(a)
-data !a
+condition !(ok)
+data !ok
-condition !!a
+condition !!ok
data ERROR offset 1 Double negation is invalid
-condition !(!a)
-data a
+condition !(!ok)
+data ok
#
# These next two are identical after normalization
#
-condition (a == b || c == d)
-data a == b || c == d
+condition (&User-Name == &User-Password || &Filter-Id == &Reply-Message)
+data &User-Name == &User-Password || &Filter-Id == &Reply-Message
-condition ((a == b) || (c == d))
-data a == b || c == d
+condition ((&User-Name == &User-Password) || (&Filter-Id == &Reply-Message))
+data &User-Name == &User-Password || &Filter-Id == &Reply-Message
-condition (!(a == b) || (c == d))
-data !a == b || c == d
+condition (!(&User-Name == &User-Password) || (&Filter-Id == &Reply-Message))
+data !&User-Name == &User-Password || &Filter-Id == &Reply-Message
# different from the previous ones.
-condition (!((a == b) || (c == d)))
-data !(a == b || c == d)
+condition (!((&User-Name == &User-Password) || (&Filter-Id == &Reply-Message)))
+data !(&User-Name == &User-Password || &Filter-Id == &Reply-Message)
-condition (!(a == b) || (c == d))
-data !a == b || c == d
+condition (!(&User-Name == &User-Password) || (&Filter-Id == &Reply-Message))
+data !&User-Name == &User-Password || &Filter-Id == &Reply-Message
condition ((a == b) || (c == d)))
data ERROR offset 22 Unexpected closing brace
condition handled &&&Response-Packet-Type == Access-Challenge
data handled && &Response-Packet-Type == Access-Challenge
-condition (!(!foo))
-data foo
-
condition /foo/ =~ bar
data ERROR offset 0 Conditional check cannot begin with a regular expression
#
# Convert != to !(COND) for normal checks
#
-condition foo == "bar"
-data foo == "bar"
+condition &User-Name == &User-Password
+data &User-Name == &User-Password
-condition foo != "bar"
-data !foo == "bar"
+condition &User-Name != &User-Password
+data !&User-Name == &User-Password
-condition !foo != "bar"
-data foo == "bar"
+condition !&User-Name != &User-Password
+data &User-Name == &User-Password
condition <ipv6addr>foo
data ERROR offset 0 Cannot do cast for existence check
condition <ipaddr>Filter-Id == <blerg>&Framed-IP-Address
data ERROR offset 22 Invalid data type in cast
+#
+# Normalize things
+#
condition <ipaddr>Filter-Id == "127.0.0.1"
-data <ipaddr>&Filter-Id == "127.0.0.1"
+data <ipaddr>&Filter-Id == '127.0.0.1'
condition <ipaddr>127.0.0.1 < &Framed-IP-Address
-data <ipaddr>127.0.0.1 < &Framed-IP-Address
+data &Framed-IP-Address > 127.0.0.1
# =* and !* are only for attrs / lists
condition "foo" !* bar
data ERROR offset 19 Value must be an unquoted string
# Except for dates, which can be humanly readable!
-# This one MIGHT be an expansion, so it's left as-is.
-condition Event-Timestamp == "January 1, 2012"
-data &Event-Timestamp == "January 1, 2012"
+# This one is be an expansion, so it's left as-is.
+condition Event-Timestamp == "January 1, 2012 %{blah}"
+data &Event-Timestamp == "January 1, 2012 %{blah}"
# This one is NOT an expansion, so it's parsed into normal form
condition Event-Timestamp == 'January 1, 2012'
-#data &Event-Timestamp == "Jan 1 2012 00:00:00 EST"
+#data &Event-Timestamp == 'Jan 1 2012 00:00:00 EST'
# literals are parsed when the conditions are parsed
condition <integer>X == 1
condition NAS-Port == X
data ERROR offset 12 Failed to parse value for attribute
+#
+# The RHS is a static string, so this gets mashed to a literal,
+# and then statically evaluated.
+#
condition <ipaddr>127.0.0.1 == "127.0.0.1"
-data <ipaddr>127.0.0.1 == "127.0.0.1"
+data true
+
+condition <ipaddr>127.0.0.1 == "%{sql: 127.0.0.1}"
+data <ipaddr>127.0.0.1 == "%{sql: 127.0.0.1}"
condition <ether> 00:11:22:33:44:55 == "00:11:22:33:44:55"
-data <ether>00:11:22:33:44:55 == "00:11:22:33:44:55"
+data true
+
+condition <ether> 00:11:22:33:44:55 == "ff:11:22:33:44:55"
+data false
+
+condition <ether> 00:11:22:33:44:55 == "%{sql:00:11:22:33:44:55}"
+data <ether>00:11:22:33:44:55 == "%{sql:00:11:22:33:44:55}"
condition <ether> 00:XX:22:33:44:55 == 00:11:22:33:44:55
data ERROR offset 8 Failed to parse field
data true
#
-# Both sides literals: evaluate at parse time.
+# Both sides static data with a cast: evaluate at parse time.
#
condition <integer>20 < 100
data true
+
+#
+# Both sides literal: evaluate at parse time
+#
+condition ('foo' == 'bar')
+data false
+
+condition ('foo' < 'bar')
+data false
+
+condition ('foo' > 'bar')
+data true
+
+condition ('foo' == 'foo')
+data true
+
+#
+# Double-quotes strings without expansions are literals
+#
+condition ("foo" == "%{sql: foo}")
+data foo == "%{sql: foo}"
+
+condition ("foo bar" == "%{sql: foo}")
+data 'foo bar' == "%{sql: foo}"
+
+condition ("foo" == "bar")
+data false
+
+condition ("foo" == 'bar')
+data false
+
+#
+# The RHS gets parsed as a VPT_TYPE_DATA, which is
+# a double-quoted string
+#
+condition (&User-Name == "bob")
+data &User-Name == "bob"
+
+condition (&User-Name == "%{sql: blah}")
+data &User-Name == "%{sql: blah}"
+
+condition <ipaddr>127.0.0.1 == 2130706433
+data true
+
+# /32 suffix should be trimmed for this type
+condition <ipaddr>127.0.0.1/32 == 127.0.0.1
+data true
+
+condition <ipaddr>127.0.0.1/327 == 127.0.0.1
+data ERROR offset 8 Failed to parse field
+
+condition <ipaddr>127.0.0.1/32 == 127.0.0.1
+data true
+
+condition (/foo/)
+data ERROR offset 1 Conditional check cannot begin with a regular expression
+
+#
+# Tests for (FOO).
+#
+condition (1)
+data true
+
+condition (0)
+data false
+
+condition (true)
+data true
+
+condition (false)
+data false
+
+condition ('')
+data false
+
+condition ("")
+data false
+
+#
+# Integers are true, as are non-zero strings
+#
+condition (4)
+data true
+
+condition ('a')
+data true
+
+condition (a)
+data ERROR offset 1 Expected a module return code
+
+#
+# Module return codes are OK
+#
+condition (ok)
+data ok
+
+condition (handled)
+data handled
+
+condition (fail)
+data fail
+
+condition ("a")
+data true
+
+condition (`a`)
+data `a`
+
+condition (User-name)
+data &User-Name
+
+#
+# Forbidden data types in cast
+#
+condition (<vsa>"foo" == &User-Name)
+data ERROR offset 2 Forbidden data type in cast
+
+#
+# Must have attribute references on the LHS of a condition.
+#
+condition ("foo" == &User-Name)
+data ERROR offset 1 Cannot use attribute reference on right side of condition
+
+#
+# If the LHS is a cast to a type, and the RHS is an attribute
+# of the same type, then re-write it so that the attribute
+# is on the LHS of the condition.
+#
+condition <string>"foo" == &User-Name
+data &User-Name == "foo"
+
+condition <integer>"%{expr: 1 + 1}" < &NAS-Port
+data &NAS-Port > "%{expr: 1 + 1}"
+
+condition &Filter-Id == &Framed-IP-Address
+data ERROR offset 0 Attribute comparisons must be of the same data type
+
+condition <ipaddr>127.0.0.1 == &Filter-Id
+data ERROR offset 0 Attribute comparisons must be of the same data type
+
+condition <ipaddr>&Tmp-Integer64-0 == &Foo-Stuff-Bar
+data ERROR offset 0 Unknown attribute
+
+#
+# Casting attributes of different size
+#
+condition <ipaddr>&Tmp-Integer64-0 == &Framed-IP-Address
+data ERROR offset 0 Cannot cast to attribute of incompatible size
+
+condition <ipaddr>&PMIP6-Home-IPv4-HoA == &Framed-IP-Address
+data ERROR offset 0 Cannot cast to attribute of incompatible size
+
+# but these are allowed
+condition <ether>&Tmp-Integer64-0 == "%{module: foo}"
+data <ether>&Tmp-Integer64-0 == "%{module: foo}"
+
+condition <ipaddr>&Filter-Id == &Framed-IP-Address
+data <ipaddr>&Filter-Id == &Framed-IP-Address
+
+condition <ipaddr>&Class == &Framed-IP-Address
+data <ipaddr>&Class == &Framed-IP-Address
+
+#
+# Tags of zero mean restrict to attributes with no tag
+#
+condition &Tunnel-Password:0 == "Hello"
+data &Tunnel-Password:0 == "Hello"
+
+condition &Tunnel-Password:1 == "Hello"
+data &Tunnel-Password:1 == "Hello"
+
+#
+# zero offset into arrays get parsed and ignored
+#
+condition &User-Name[0] == "bob"
+data &User-Name[0] == "bob"
+
+condition &User-Name[1] == "bob"
+data &User-Name[1] == "bob"
+
+condition &Tunnel-Password:1[0] == "Hello"
+data &Tunnel-Password:1[0] == "Hello"
+
+condition &Tunnel-Password:1[3] == "Hello"
+data &Tunnel-Password:1[3] == "Hello"
# except for CUI. Thank you, WiMAX!
decode 59 02
-data Chargeable-User-Identity = ''
+data Chargeable-User-Identity = 0x
# Hah! Thought you had it figured out, didn't you?
encode -
data 59 02
+attribute Framed-IP-Address = 127.0.0.1/32
+data Framed-IP-Address = 127.0.0.1
+
+attribute Framed-IP-Address = 127.0.0.1/323
+data Invalid IPv4 mask length "/323". Should be between 0-32
+
+attribute Framed-IP-Address = 127.0.0.1/30
+data Invalid IPv4 mask length "/30". Only "/32" permitted for non-prefix types
+
+attribute Framed-IP-Address = *
+data Framed-IP-Address = 0.0.0.0
+
+attribute Framed-IP-Address = 127
+data Framed-IP-Address = 0.0.0.127
+
+attribute Framed-IPv6-Prefix = ::1
+data Framed-IPv6-Prefix = ::1/128
+
+attribute Framed-IPv6-Prefix = ::1/200
+data Invalid IPv6 mask length "/200". Should be between 0-128
+
+attribute Framed-IPv6-Prefix = ::1/200
+data Invalid IPv6 mask length "/200". Should be between 0-128
+
+attribute Framed-IPv6-Prefix = 11:22:33:44:55:66:77:88/128
+data Framed-IPv6-Prefix = 11:22:33:44:55:66:77:88/128
+
+attribute Framed-IPv6-Prefix = *
+data Framed-IPv6-Prefix = ::/128
+
$INCLUDE errors.txt
$INCLUDE extended.txt
$INCLUDE lucent.txt
xlat "%{Foreach-Variable-0}"
data "%{Foreach-Variable-0}"
+
+#
+# 3GPP stuff, to distinguish "list:3GPP" from
+# "attribute:tag"
+#
+xlat "%{request:3GPP-IMSI}"
+data "%{3GPP-IMSI}"
+
+xlat "%{reply:3GPP-IMSI}"
+data "%{reply:3GPP-IMSI}"
+
+xlat "%{reply:3GPP-IMSI[2]}"
+data "%{reply:3GPP-IMSI[2]}"
Name: freeradius-server
-Version: 3.0.1
+Version: 3.0.3
Release: 0
License: GPLv2 ; LGPLv2.1
Group: Productivity/Networking/Radius/Servers
BuildRequires: glibc-devel
BuildRequires: libtalloc-devel
BuildRequires: openldap2-devel
+BuildRequires: openssl
BuildRequires: openssl-devel
BuildRequires: pam-devel
BuildRequires: perl
%{_sysconfdir}/init.d/freeradius
%config %{_sysconfdir}/pam.d/radiusd
%config %{_sysconfdir}/logrotate.d/freeradius-server
+%dir %{_sysconfdir}/tmpfiles.d
%config %{_sysconfdir}/tmpfiles.d/radiusd.conf
%dir %attr(755,radiusd,radiusd) %{_localstatedir}/lib/radiusd
# configs
%attr(755,root,root) %{_libdir}/freeradius/rlm_*.so*
%files utils
+%defattr(-,root,root)
/usr/bin/*
%files libs
# RADIUS shared libs
%attr(755,root,root) %dir %{_libdir}/freeradius
-%attr(755,root,root) %{_libdir}/freeradius/*.so*
+%attr(755,root,root) %{_libdir}/freeradius/lib*.so*
+%attr(755,root,root) %{_libdir}/freeradius/proto*.so*
%files devel
%defattr(-,root,root)
+%dir /usr/include/freeradius
%attr(644,root,root) /usr/include/freeradius/*.h