Merge tag 'release_3_0_12' into branch moonshot-fr-3.0.12-upgrade.
authorDan Breslau <dbreslau@painless-security.com>
Fri, 27 Jan 2017 16:19:35 +0000 (11:19 -0500)
committerDan Breslau <dbreslau@painless-security.com>
Fri, 27 Jan 2017 16:19:35 +0000 (11:19 -0500)
Conflicts:
src/modules/rlm_realm/rlm_realm.c

256 files changed:
.gitattributes
Make.inc.in
Makefile
VERSION
aclocal.m4
configure
configure.ac
debian/changelog
debian/control
debian/freeradius-dhcp.postinst [changed mode: 0755->0644]
debian/freeradius-iodbc.postinst [changed mode: 0755->0644]
debian/freeradius-krb5.postinst [changed mode: 0755->0644]
debian/freeradius-ldap.postinst [changed mode: 0755->0644]
debian/freeradius-memcached.postinst [changed mode: 0755->0644]
debian/freeradius-mysql.postinst [changed mode: 0755->0644]
debian/freeradius-postgresql.postinst [changed mode: 0755->0644]
debian/freeradius-redis.postinst [changed mode: 0755->0644]
debian/freeradius-rest.postinst [changed mode: 0755->0644]
debian/freeradius-yubikey.postinst [changed mode: 0755->0644]
debian/freeradius.default
debian/freeradius.init
debian/freeradius.logrotate
debian/freeradius.postinst [changed mode: 0755->0644]
debian/freeradius.postrm [changed mode: 0755->0644]
debian/freeradius.prerm [changed mode: 0755->0644]
debian/freeradius.service [new file with mode: 0644]
debian/patches/logrotate-path.diff [deleted file]
debian/patches/radiusd-to-freeradius.diff
debian/patches/series
debian/rules
debian/source/lintian-overrides [new file with mode: 0644]
doc/ChangeLog
doc/README
doc/modules/ldap_howto.rst
doc/schemas/logstash/README
doc/schemas/logstash/kibana3-dashboard.json [new file with mode: 0644]
doc/schemas/logstash/kibana4-dashboard.json [new file with mode: 0644]
doc/schemas/logstash/log-courier.conf [new file with mode: 0644]
doc/schemas/logstash/logstash-radius.conf [new file with mode: 0644]
doc/schemas/logstash/radius-mapping.sh [changed mode: 0644->0755]
doc/schemas/logstash/radius.conf [deleted file]
install-sh
man/man1/dhcpclient.1 [new file with mode: 0644]
man/man1/rad_counter.1 [new file with mode: 0644]
man/man5/unlang.5
mibs/FREERADIUS-NOTIFICATION-MIB.mib
mibs/RADIUS-STAT-MIB.mib
raddb/README.rst
raddb/all.mk
raddb/certs/Makefile
raddb/mods-available/cache
raddb/mods-available/eap
raddb/mods-available/ldap
raddb/mods-available/sql
raddb/mods-config/attr_filter/pre-proxy
raddb/mods-config/perl/example.pl
raddb/mods-config/sql/main/mssql/schema.sql
raddb/mods-config/sql/main/mysql/queries.conf
raddb/mods-config/sql/main/mysql/schema.sql
raddb/mods-config/sql/main/oracle/queries.conf
raddb/mods-config/sql/main/postgresql/queries.conf
raddb/mods-config/sql/main/sqlite/queries.conf
raddb/policy.d/abfab-tr
raddb/policy.d/accounting
raddb/policy.d/debug
raddb/policy.d/filter
raddb/policy.d/moonshot-targeted-ids [new file with mode: 0644]
raddb/sites-available/abfab-tr-idp
raddb/sites-available/check-eap-tls
raddb/sites-available/default
raddb/sites-available/inner-tunnel
raddb/sites-available/virtual.example.com
redhat/freeradius.spec-renamed
scripts/boiler.mk
scripts/collectd/radsniff_types.db [new file with mode: 0644]
scripts/install.mk
scripts/jlibtool.c
scripts/libtool.mk
scripts/monit/freeradius.monitrc
scripts/munin/radsniff [new file with mode: 0755]
scripts/raddebug
scripts/sql/radsqlrelay
share/dictionary
share/dictionary.3gpp
share/dictionary.adtran [new file with mode: 0644]
share/dictionary.arista
share/dictionary.aruba
share/dictionary.checkpoint [new file with mode: 0644]
share/dictionary.freeradius
share/dictionary.freeradius.internal
share/dictionary.hillstone [new file with mode: 0644]
share/dictionary.hp
share/dictionary.huawei
share/dictionary.lancom
share/dictionary.lantronix [new file with mode: 0644]
share/dictionary.meraki [new file with mode: 0644]
share/dictionary.rfc4072
share/dictionary.rfc4372
share/dictionary.rfc4675
share/dictionary.rfc4679
share/dictionary.ruckus
share/dictionary.sangoma [new file with mode: 0644]
share/dictionary.starent
share/dictionary.wichorus
src/all.mk
src/include/.gitignore
src/include/all.mk
src/include/autoconf.h.in
src/include/build.h
src/include/conffile.h
src/include/libradius.h
src/include/missing-h
src/include/modcall.h
src/include/radius.h
src/include/radiusd.h
src/include/threads.h
src/include/tls-h
src/lib/cursor.c
src/lib/debug.c
src/lib/dict.c
src/lib/log.c
src/lib/misc.c
src/lib/missing.c
src/lib/packet.c
src/lib/pair.c
src/lib/print.c
src/lib/radius.c
src/lib/tcp.c
src/lib/token.c
src/lib/value.c
src/main/.gitignore
src/main/auth.c
src/main/cb.c
src/main/checkrad.mk
src/main/client.c
src/main/command.c
src/main/conffile.c
src/main/connection.c
src/main/detail.c
src/main/evaluate.c
src/main/exec.c
src/main/exfile.c
src/main/libfreeradius-server.mk
src/main/listen.c
src/main/mainconfig.c
src/main/map.c
src/main/modcall.c
src/main/modules.c
src/main/pair.c
src/main/parser.c
src/main/process.c
src/main/radclient.c
src/main/radiusd.c
src/main/radiusd.mk
src/main/radlast.mk
src/main/radmin.c
src/main/radsniff.c
src/main/radtest.mk
src/main/radwho.c
src/main/radzap.mk
src/main/realms.c
src/main/session.c
src/main/soh.c
src/main/state.c
src/main/stats.c
src/main/threads.c
src/main/tls.c
src/main/tls_listen.c
src/main/tmpl.c
src/main/unittest.c
src/main/unittest.mk
src/main/util.c
src/main/version.c
src/main/xlat.c
src/modules/.gitignore [new file with mode: 0644]
src/modules/proto_dhcp/dhcp.c
src/modules/rlm_cache/rlm_cache.c
src/modules/rlm_chap/rlm_chap.c
src/modules/rlm_couchbase/rlm_couchbase.c
src/modules/rlm_counter/all.mk.in
src/modules/rlm_detail/rlm_detail.c
src/modules/rlm_digest/rlm_digest.c
src/modules/rlm_eap/eap.c
src/modules/rlm_eap/libeap/eap_chbind.c
src/modules/rlm_eap/libeap/eap_tls.c
src/modules/rlm_eap/libeap/eap_tls.h
src/modules/rlm_eap/libeap/eapsimlib.c
src/modules/rlm_eap/libeap/mppe_keys.c
src/modules/rlm_eap/mem.c
src/modules/rlm_eap/radeapclient.c
src/modules/rlm_eap/radeapclient.mk
src/modules/rlm_eap/rlm_eap.c
src/modules/rlm_eap/types/rlm_eap_fast/all.mk [new file with mode: 0644]
src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.c [new file with mode: 0644]
src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.h [new file with mode: 0644]
src/modules/rlm_eap/types/rlm_eap_fast/eap_fast_crypto.c [new file with mode: 0644]
src/modules/rlm_eap/types/rlm_eap_fast/eap_fast_crypto.h [new file with mode: 0644]
src/modules/rlm_eap/types/rlm_eap_fast/rlm_eap_fast.c [new file with mode: 0644]
src/modules/rlm_eap/types/rlm_eap_gtc/rlm_eap_gtc.c
src/modules/rlm_eap/types/rlm_eap_md5/rlm_eap_md5.c
src/modules/rlm_eap/types/rlm_eap_mschapv2/rlm_eap_mschapv2.c
src/modules/rlm_eap/types/rlm_eap_peap/eap_peap.h
src/modules/rlm_eap/types/rlm_eap_peap/peap.c
src/modules/rlm_eap/types/rlm_eap_peap/rlm_eap_peap.c
src/modules/rlm_eap/types/rlm_eap_pwd/all.mk.in
src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c
src/modules/rlm_eap/types/rlm_eap_sim/rlm_eap_sim.c
src/modules/rlm_eap/types/rlm_eap_ttls/rlm_eap_ttls.c
src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c
src/modules/rlm_exec/rlm_exec.c
src/modules/rlm_expr/rlm_expr.c
src/modules/rlm_ldap/ldap.c
src/modules/rlm_ldap/ldap.h
src/modules/rlm_ldap/rlm_ldap.c
src/modules/rlm_linelog/rlm_linelog.c
src/modules/rlm_mschap/README [deleted file]
src/modules/rlm_mschap/auth_wbclient.c
src/modules/rlm_mschap/auth_wbclient.h
src/modules/rlm_mschap/configure
src/modules/rlm_mschap/configure.ac
src/modules/rlm_mschap/rlm_mschap.c
src/modules/rlm_pap/rlm_pap.c
src/modules/rlm_perl/rlm_perl.c
src/modules/rlm_python/configure
src/modules/rlm_python/configure.ac
src/modules/rlm_python/example.py
src/modules/rlm_python/prepaid.py
src/modules/rlm_python/radiusd.py
src/modules/rlm_python/rlm_python.c
src/modules/rlm_realm/rlm_realm.c
src/modules/rlm_rest/rest.c
src/modules/rlm_rest/rlm_rest.c
src/modules/rlm_ruby/rlm_ruby.c
src/modules/rlm_sql/README [deleted file]
src/modules/rlm_sql/drivers/rlm_sql_mysql/rlm_sql_mysql.c
src/modules/rlm_sql/drivers/rlm_sql_oracle/rlm_sql_oracle.c
src/modules/rlm_sql/drivers/rlm_sql_postgresql/rlm_sql_postgresql.c
src/modules/rlm_sql/drivers/rlm_sql_sqlite/rlm_sql_sqlite.c
src/modules/rlm_sql/rlm_sql.c
src/modules/rlm_sql/sql.c
src/modules/rlm_sql/stable
src/modules/rlm_sqlcounter/rlm_sqlcounter.c
src/modules/rlm_sqlippool/rlm_sqlippool.c
src/tests/.gitignore
src/tests/keywords/case-attr-error [new file with mode: 0644]
src/tests/keywords/regex-escape [new file with mode: 0644]
src/tests/keywords/regex-lhs [new file with mode: 0644]
src/tests/keywords/string [new file with mode: 0644]
src/tests/keywords/update-filter [new file with mode: 0644]
src/tests/map/map_tests.mk
src/tests/modules/sql/README [deleted file]
src/tests/rbmonkey.mk
src/tests/unit/condition.txt
src/tests/unit/errors.txt
src/tests/unit/rfc.txt
suse/freeradius.spec-renamed

index 035d6c6..a76baa9 100644 (file)
@@ -1,2 +1,5 @@
 *      text=auto
 *      ident
+*.h    linguist-language=c
+*.c    linguist-language=c
+doc/*  linguist-documentation
index a06a044..7a77625 100644 (file)
@@ -47,11 +47,11 @@ MAKEFLAGS   = @FR_MAKEFLAGS@
 
 CC             = @CC@
 RANLIB         = @RANLIB@
-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
+INCLUDE                = -I. -Isrc \
+                 -include src/freeradius-devel/autoconf.h \
+                 -include src/freeradius-devel/build.h \
+                 -include src/freeradius-devel/features.h \
+                 -include src/freeradius-devel/radpaths.h
 CFLAGS         = $(INCLUDE) -fno-strict-aliasing @CFLAGS@
 CPPFLAGS       = @CPPFLAGS@
 LIBPREFIX      = @LIBPREFIX@
@@ -163,7 +163,7 @@ ANALYZE.c       := @clang_path@
 #
 ifeq "$(USE_SHARED_LIBS)" "yes"
        TESTBINDIR = ./$(BUILD_DIR)/bin/local
-       TESTBIN    = $(JLIBTOOL) --quiet --mode=execute $(TESTBINDIR)
+       TESTBIN    =  FR_LIBRARY_PATH=./build/lib/.libs $(JLIBTOOL) --quiet --mode=execute $(TESTBINDIR)
 else
        TESTBINDIR = ./$(BUILD_DIR)/bin
        TESTBIN    = ./$(BUILD_DIR)/bin
index bc0150f..20a2e4d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -7,6 +7,11 @@
 # Version:     $Id$
 #
 
+#
+#  The default rule is "all".
+#
+all:
+
 $(if $(wildcard Make.inc),,$(error Missing 'Make.inc' Run './configure [options]' and retry))
 
 include Make.inc
@@ -42,7 +47,7 @@ raddb/test.conf:
 $(BUILD_DIR)/tests/radiusd-c: raddb/test.conf ${BUILD_DIR}/bin/radiusd | build.raddb
        @$(MAKE) -C raddb/certs
        @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 \
+       @if ! FR_LIBRARY_PATH=./build/lib/local/.libs/ ./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"; \
@@ -59,7 +64,7 @@ test: ${BUILD_DIR}/bin/radiusd ${BUILD_DIR}/bin/radclient tests.unit tests.xlat
 # Â the above tests
 ifneq "$(findstring travis,${prefix})" ""
 travis-test: raddb/test.conf test
-       @./build/make/jlibtool --mode=execute ./build/bin/radiusd -xxxv -n test
+       @FR_LIBRARY_PATH=./build/lib/local/.libs/ ./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
@@ -85,23 +90,6 @@ endif
 #
 export DESTDIR := $(R)
 
-.PHONY: install.bindir
-install.bindir:
-       @[ -d $(R)$(bindir) ] || $(INSTALL) -d -m 755 $(R)$(bindir)
-
-.PHONY: install.sbindir
-install.sbindir:
-       @[ -d $(R)$(sbindir) ] || $(INSTALL) -d -m 755 $(R)$(sbindir)
-
-.PHONY: install.dirs
-install.dirs: install.bindir install.sbindir
-       @$(INSTALL) -d -m 755   $(R)$(mandir)
-       @$(INSTALL) -d -m 755   $(R)$(RUNDIR)
-       @$(INSTALL) -d -m 700   $(R)$(logdir)
-       @$(INSTALL) -d -m 700   $(R)$(radacctdir)
-       @$(INSTALL) -d -m 755   $(R)$(datadir)
-       @$(INSTALL) -d -m 755   $(R)$(dictdir)
-
 DICTIONARIES := $(wildcard share/dictionary*)
 install.share: $(addprefix $(R)$(dictdir)/,$(notdir $(DICTIONARIES)))
 
@@ -114,14 +102,20 @@ install.man: $(subst man/,$(R)$(mandir)/,$(MANFILES))
 
 $(R)$(mandir)/%: man/%
        @echo INSTALL $(notdir $<)
-       @$(INSTALL) -m 644 $< $@
+       @sed -e "s,/etc/raddb,$(raddbdir),g" \
+               -e "s,/usr/local/share,$(datarootdir),g" \
+               $< > $<.subst
+       @$(INSTALL) -m 644 $<.subst $@
+       @rm $<.subst
 
 #
 #  Don't install rlm_test
 #
 ALL_INSTALL := $(patsubst %rlm_test.la,,$(ALL_INSTALL))
 
-install: install.dirs install.share install.man
+install: install.share install.man
+       @$(INSTALL) -d -m 700   $(R)$(logdir)
+       @$(INSTALL) -d -m 700   $(R)$(radacctdir)
 
 ifneq ($(RADMIN),)
 ifneq ($(RGROUP),)
@@ -249,14 +243,11 @@ BRANCH = $(shell git rev-parse --abbrev-ref HEAD)
 freeradius-server-$(RADIUSD_VERSION_STRING).tar.gz: .git
        git archive --format=tar --prefix=freeradius-server-$(RADIUSD_VERSION_STRING)/ $(BRANCH) | gzip > $@
 
-freeradius-server-$(RADIUSD_VERSION_STRING).tar.gz.sig: freeradius-server-$(RADIUSD_VERSION_STRING).tar.gz
-       gpg --default-key aland@freeradius.org -b $<
-
 freeradius-server-$(RADIUSD_VERSION_STRING).tar.bz2: .git
        git archive --format=tar --prefix=freeradius-server-$(RADIUSD_VERSION_STRING)/ $(BRANCH) | bzip2 > $@
 
-freeradius-server-$(RADIUSD_VERSION_STRING).tar.bz2.sig: freeradius-server-$(RADIUSD_VERSION_STRING).tar.bz2
-       gpg --default-key aland@freeradius.org -b $<
+%.sig: %
+       gpg --default-key packages@freeradius.org -b $<
 
 # high-level targets
 .PHONY: dist-check
diff --git a/VERSION b/VERSION
index a909317..f93fc9f 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.0.10
+3.0.12
index a803eaf..440da76 100644 (file)
-# generated automatically by aclocal 1.11.1 -*- Autoconf -*-
-
-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-# 2005, 2006, 2007, 2008, 2009  Free Software Foundation, Inc.
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
-#
-#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
-#                 2006, 2007, 2008, 2009, 2010 Free Software Foundation,
-#                 Inc.
-#   Written by Gordon Matzigkeit, 1996
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-m4_define([_LT_COPYING], [dnl
-#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
-#                 2006, 2007, 2008, 2009, 2010 Free Software Foundation,
-#                 Inc.
-#   Written by Gordon Matzigkeit, 1996
-#
-#   This file is part of GNU Libtool.
-#
-# GNU Libtool 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.
-#
-# As a special exception to the GNU General Public License,
-# if you distribute this file as part of a program or library that
-# is built using GNU Libtool, you may include this file under the
-# same distribution terms that you use for the rest of that program.
-#
-# GNU Libtool 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 GNU Libtool; see the file COPYING.  If not, a copy
-# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
-# obtained by writing to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-])
-
-# serial 57 LT_INIT
-
-
-# LT_PREREQ(VERSION)
-# ------------------
-# Complain and exit if this libtool version is less that VERSION.
-m4_defun([LT_PREREQ],
-[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
-       [m4_default([$3],
-                  [m4_fatal([Libtool version $1 or higher is required],
-                            63)])],
-       [$2])])
-
-
-# _LT_CHECK_BUILDDIR
-# ------------------
-# Complain if the absolute build directory name contains unusual characters
-m4_defun([_LT_CHECK_BUILDDIR],
-[case `pwd` in
-  *\ * | *\    *)
-    AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
-esac
-])
-
-
-# LT_INIT([OPTIONS])
-# ------------------
-AC_DEFUN([LT_INIT],
-[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
-AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
-AC_BEFORE([$0], [LT_LANG])dnl
-AC_BEFORE([$0], [LT_OUTPUT])dnl
-AC_BEFORE([$0], [LTDL_INIT])dnl
-m4_require([_LT_CHECK_BUILDDIR])dnl
-
-dnl Autoconf doesn't catch unexpanded LT_ macros by default:
-m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
-m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
-dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
-dnl unless we require an AC_DEFUNed macro:
-AC_REQUIRE([LTOPTIONS_VERSION])dnl
-AC_REQUIRE([LTSUGAR_VERSION])dnl
-AC_REQUIRE([LTVERSION_VERSION])dnl
-AC_REQUIRE([LTOBSOLETE_VERSION])dnl
-
-_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
-
-dnl Parse OPTIONS
-_LT_SET_OPTIONS([$0], [$1])
-
-_LT_SETUP
-
-# Only expand once:
-m4_define([LT_INIT])
-])# LT_INIT
-
-# Old names:
-AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
-AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
-dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
-
-
-# _LT_CC_BASENAME(CC)
-# -------------------
-# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
-m4_defun([_LT_CC_BASENAME],
-[for cc_temp in $1""; do
-  case $cc_temp in
-    compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
-    distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
-    \-*) ;;
-    *) break;;
-  esac
-done
-cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
-])
-
-
-# _LT_FILEUTILS_DEFAULTS
-# ----------------------
-# It is okay to use these file commands and assume they have been set
-# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
-m4_defun([_LT_FILEUTILS_DEFAULTS],
-[: ${CP="cp -f"}
-: ${MV="mv -f"}
-: ${RM="rm -f"}
-])# _LT_FILEUTILS_DEFAULTS
-
-
-# _LT_SETUP
-# ---------
-m4_defun([_LT_SETUP],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
-AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
-
-_LT_DECL([], [host_alias], [0], [The host system])dnl
-_LT_DECL([], [host], [0])dnl
-_LT_DECL([], [host_os], [0])dnl
-dnl
-_LT_DECL([], [build_alias], [0], [The build system])dnl
-_LT_DECL([], [build], [0])dnl
-_LT_DECL([], [build_os], [0])dnl
-dnl
-AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([LT_PATH_LD])dnl
-AC_REQUIRE([LT_PATH_NM])dnl
-dnl
-AC_REQUIRE([AC_PROG_LN_S])dnl
-test -z "$LN_S" && LN_S="ln -s"
-_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
-dnl
-AC_REQUIRE([LT_CMD_MAX_LEN])dnl
-_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
-_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
-dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_CHECK_SHELL_FEATURES])dnl
-m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
-m4_require([_LT_CMD_RELOAD])dnl
-m4_require([_LT_CHECK_MAGIC_METHOD])dnl
-m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
-m4_require([_LT_CMD_OLD_ARCHIVE])dnl
-m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
-m4_require([_LT_WITH_SYSROOT])dnl
-
-_LT_CONFIG_LIBTOOL_INIT([
-# See if we are running on zsh, and set the options which allow our
-# commands through without removal of \ escapes INIT.
-if test -n "\${ZSH_VERSION+set}" ; then
-   setopt NO_GLOB_SUBST
-fi
-])
-if test -n "${ZSH_VERSION+set}" ; then
-   setopt NO_GLOB_SUBST
-fi
-
-_LT_CHECK_OBJDIR
-
-m4_require([_LT_TAG_COMPILER])dnl
-
-case $host_os in
-aix3*)
-  # AIX sometimes has problems with the GCC collect2 program.  For some
-  # reason, if we set the COLLECT_NAMES environment variable, the problems
-  # vanish in a puff of smoke.
-  if test "X${COLLECT_NAMES+set}" != Xset; then
-    COLLECT_NAMES=
-    export COLLECT_NAMES
-  fi
-  ;;
-esac
-
-# Global variables:
-ofile=libtool
-can_build_shared=yes
-
-# All known linkers require a `.a' archive for static linking (except MSVC,
-# which needs '.lib').
-libext=a
-
-with_gnu_ld="$lt_cv_prog_gnu_ld"
-
-old_CC="$CC"
-old_CFLAGS="$CFLAGS"
-
-# Set sane defaults for various variables
-test -z "$CC" && CC=cc
-test -z "$LTCC" && LTCC=$CC
-test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
-test -z "$LD" && LD=ld
-test -z "$ac_objext" && ac_objext=o
-
-_LT_CC_BASENAME([$compiler])
-
-# Only perform the check for file, if the check method requires it
-test -z "$MAGIC_CMD" && MAGIC_CMD=file
-case $deplibs_check_method in
-file_magic*)
-  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
-    _LT_PATH_MAGIC
-  fi
-  ;;
-esac
-
-# Use C for the default configuration in the libtool script
-LT_SUPPORTED_TAG([CC])
-_LT_LANG_C_CONFIG
-_LT_LANG_DEFAULT_CONFIG
-_LT_CONFIG_COMMANDS
-])# _LT_SETUP
-
-
-# _LT_PREPARE_SED_QUOTE_VARS
-# --------------------------
-# Define a few sed substitution that help us do robust quoting.
-m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
-[# Backslashify metacharacters that are still active within
-# double-quoted strings.
-sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
-
-# Same as above, but do not quote variable references.
-double_quote_subst='s/\([["`\\]]\)/\\\1/g'
-
-# Sed substitution to delay expansion of an escaped shell variable in a
-# double_quote_subst'ed string.
-delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
-
-# Sed substitution to delay expansion of an escaped single quote.
-delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
-
-# Sed substitution to avoid accidental globbing in evaled expressions
-no_glob_subst='s/\*/\\\*/g'
-])
-
-
-# So that we can recreate a full libtool script including additional
-# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
-# in macros and then make a single call at the end using the `libtool'
-# label.
-
-
-# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
-# ----------------------------------------
-# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
-m4_define([_LT_CONFIG_LIBTOOL_INIT],
-[m4_ifval([$1],
-          [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
-                     [$1
-])])])
-
-# Initialize.
-m4_define([_LT_OUTPUT_LIBTOOL_INIT])
-
-
-# _LT_CONFIG_LIBTOOL([COMMANDS])
-# ------------------------------
-# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
-m4_define([_LT_CONFIG_LIBTOOL],
-[m4_ifval([$1],
-          [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
-                     [$1
-])])])
-
-# Initialize.
-m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
-
-
-# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
-# -----------------------------------------------------
-m4_defun([_LT_CONFIG_SAVE_COMMANDS],
-[_LT_CONFIG_LIBTOOL([$1])
-_LT_CONFIG_LIBTOOL_INIT([$2])
-])
-
-
-# _LT_FORMAT_COMMENT([COMMENT])
-# -----------------------------
-# Add leading comment marks to the start of each line, and a trailing
-# full-stop to the whole comment if one is not present already.
-m4_define([_LT_FORMAT_COMMENT],
-[m4_ifval([$1], [
-m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
-              [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
-)])
-
-
-
-
-
-# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
-# -------------------------------------------------------------------
-# CONFIGNAME is the name given to the value in the libtool script.
-# VARNAME is the (base) name used in the configure script.
-# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
-# VARNAME.  Any other value will be used directly.
-m4_define([_LT_DECL],
-[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
-    [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
-       [m4_ifval([$1], [$1], [$2])])
-    lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
-    m4_ifval([$4],
-       [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
-    lt_dict_add_subkey([lt_decl_dict], [$2],
-       [tagged?], [m4_ifval([$5], [yes], [no])])])
-])
-
-
-# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
-# --------------------------------------------------------
-m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
-
-
-# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
-# ------------------------------------------------
-m4_define([lt_decl_tag_varnames],
-[_lt_decl_filter([tagged?], [yes], $@)])
-
-
-# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
-# ---------------------------------------------------------
-m4_define([_lt_decl_filter],
-[m4_case([$#],
-  [0], [m4_fatal([$0: too few arguments: $#])],
-  [1], [m4_fatal([$0: too few arguments: $#: $1])],
-  [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
-  [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
-  [lt_dict_filter([lt_decl_dict], $@)])[]dnl
-])
-
-
-# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
-# --------------------------------------------------
-m4_define([lt_decl_quote_varnames],
-[_lt_decl_filter([value], [1], $@)])
-
-
-# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
-# ---------------------------------------------------
-m4_define([lt_decl_dquote_varnames],
-[_lt_decl_filter([value], [2], $@)])
-
-
-# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
-# ---------------------------------------------------
-m4_define([lt_decl_varnames_tagged],
-[m4_assert([$# <= 2])dnl
-_$0(m4_quote(m4_default([$1], [[, ]])),
-    m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
-    m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
-m4_define([_lt_decl_varnames_tagged],
-[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
-
-
-# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
-# ------------------------------------------------
-m4_define([lt_decl_all_varnames],
-[_$0(m4_quote(m4_default([$1], [[, ]])),
-     m4_if([$2], [],
-          m4_quote(lt_decl_varnames),
-       m4_quote(m4_shift($@))))[]dnl
-])
-m4_define([_lt_decl_all_varnames],
-[lt_join($@, lt_decl_varnames_tagged([$1],
-                       lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
-])
-
-
-# _LT_CONFIG_STATUS_DECLARE([VARNAME])
-# ------------------------------------
-# Quote a variable value, and forward it to `config.status' so that its
-# declaration there will have the same value as in `configure'.  VARNAME
-# must have a single quote delimited value for this to work.
-m4_define([_LT_CONFIG_STATUS_DECLARE],
-[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
-
-
-# _LT_CONFIG_STATUS_DECLARATIONS
-# ------------------------------
-# We delimit libtool config variables with single quotes, so when
-# we write them to config.status, we have to be sure to quote all
-# embedded single quotes properly.  In configure, this macro expands
-# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
-#
-#    <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
-m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
-[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
-    [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
-
-
-# _LT_LIBTOOL_TAGS
-# ----------------
-# Output comment and list of tags supported by the script
-m4_defun([_LT_LIBTOOL_TAGS],
-[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
-available_tags="_LT_TAGS"dnl
-])
-
-
-# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
-# -----------------------------------
-# Extract the dictionary values for VARNAME (optionally with TAG) and
-# expand to a commented shell variable setting:
-#
-#    # Some comment about what VAR is for.
-#    visible_name=$lt_internal_name
-m4_define([_LT_LIBTOOL_DECLARE],
-[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
-                                          [description])))[]dnl
-m4_pushdef([_libtool_name],
-    m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
-m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
-    [0], [_libtool_name=[$]$1],
-    [1], [_libtool_name=$lt_[]$1],
-    [2], [_libtool_name=$lt_[]$1],
-    [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
-m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
-])
-
-
-# _LT_LIBTOOL_CONFIG_VARS
-# -----------------------
-# Produce commented declarations of non-tagged libtool config variables
-# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
-# script.  Tagged libtool config variables (even for the LIBTOOL CONFIG
-# section) are produced by _LT_LIBTOOL_TAG_VARS.
-m4_defun([_LT_LIBTOOL_CONFIG_VARS],
-[m4_foreach([_lt_var],
-    m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
-    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
-
-
-# _LT_LIBTOOL_TAG_VARS(TAG)
-# -------------------------
-m4_define([_LT_LIBTOOL_TAG_VARS],
-[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
-    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
-
-
-# _LT_TAGVAR(VARNAME, [TAGNAME])
-# ------------------------------
-m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
-
-
-# _LT_CONFIG_COMMANDS
-# -------------------
-# Send accumulated output to $CONFIG_STATUS.  Thanks to the lists of
-# variables for single and double quote escaping we saved from calls
-# to _LT_DECL, we can put quote escaped variables declarations
-# into `config.status', and then the shell code to quote escape them in
-# for loops in `config.status'.  Finally, any additional code accumulated
-# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
-m4_defun([_LT_CONFIG_COMMANDS],
-[AC_PROVIDE_IFELSE([LT_OUTPUT],
-       dnl If the libtool generation code has been placed in $CONFIG_LT,
-       dnl instead of duplicating it all over again into config.status,
-       dnl then we will have config.status run $CONFIG_LT later, so it
-       dnl needs to know what name is stored there:
-        [AC_CONFIG_COMMANDS([libtool],
-            [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
-    dnl If the libtool generation code is destined for config.status,
-    dnl expand the accumulated commands and init code now:
-    [AC_CONFIG_COMMANDS([libtool],
-        [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
-])#_LT_CONFIG_COMMANDS
-
-
-# Initialize.
-m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
-[
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-sed_quote_subst='$sed_quote_subst'
-double_quote_subst='$double_quote_subst'
-delay_variable_subst='$delay_variable_subst'
-_LT_CONFIG_STATUS_DECLARATIONS
-LTCC='$LTCC'
-LTCFLAGS='$LTCFLAGS'
-compiler='$compiler_DEFAULT'
-
-# A function that is used when there is no print builtin or printf.
-func_fallback_echo ()
-{
-  eval 'cat <<_LTECHO_EOF
-\$[]1
-_LTECHO_EOF'
-}
-
-# Quote evaled strings.
-for var in lt_decl_all_varnames([[ \
-]], lt_decl_quote_varnames); do
-    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
-    *[[\\\\\\\`\\"\\\$]]*)
-      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
-      ;;
-    *)
-      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
-      ;;
-    esac
-done
-
-# Double-quote double-evaled strings.
-for var in lt_decl_all_varnames([[ \
-]], lt_decl_dquote_varnames); do
-    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
-    *[[\\\\\\\`\\"\\\$]]*)
-      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
-      ;;
-    *)
-      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
-      ;;
-    esac
-done
-
-_LT_OUTPUT_LIBTOOL_INIT
-])
-
-# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
-# ------------------------------------
-# Generate a child script FILE with all initialization necessary to
-# reuse the environment learned by the parent script, and make the
-# file executable.  If COMMENT is supplied, it is inserted after the
-# `#!' sequence but before initialization text begins.  After this
-# macro, additional text can be appended to FILE to form the body of
-# the child script.  The macro ends with non-zero status if the
-# file could not be fully written (such as if the disk is full).
-m4_ifdef([AS_INIT_GENERATED],
-[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
-[m4_defun([_LT_GENERATED_FILE_INIT],
-[m4_require([AS_PREPARE])]dnl
-[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
-[lt_write_fail=0
-cat >$1 <<_ASEOF || lt_write_fail=1
-#! $SHELL
-# Generated by $as_me.
-$2
-SHELL=\${CONFIG_SHELL-$SHELL}
-export SHELL
-_ASEOF
-cat >>$1 <<\_ASEOF || lt_write_fail=1
-AS_SHELL_SANITIZE
-_AS_PREPARE
-exec AS_MESSAGE_FD>&1
-_ASEOF
-test $lt_write_fail = 0 && chmod +x $1[]dnl
-m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
-
-# LT_OUTPUT
-# ---------
-# This macro allows early generation of the libtool script (before
-# AC_OUTPUT is called), incase it is used in configure for compilation
-# tests.
-AC_DEFUN([LT_OUTPUT],
-[: ${CONFIG_LT=./config.lt}
-AC_MSG_NOTICE([creating $CONFIG_LT])
-_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
-[# Run this file to recreate a libtool stub with the current configuration.])
-
-cat >>"$CONFIG_LT" <<\_LTEOF
-lt_cl_silent=false
-exec AS_MESSAGE_LOG_FD>>config.log
-{
-  echo
-  AS_BOX([Running $as_me.])
-} >&AS_MESSAGE_LOG_FD
-
-lt_cl_help="\
-\`$as_me' creates a local libtool stub from the current configuration,
-for use in further configure time tests before the real libtool is
-generated.
-
-Usage: $[0] [[OPTIONS]]
-
-  -h, --help      print this help, then exit
-  -V, --version   print version number, then exit
-  -q, --quiet     do not print progress messages
-  -d, --debug     don't remove temporary files
-
-Report bugs to <bug-libtool@gnu.org>."
-
-lt_cl_version="\
-m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
-m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
-configured by $[0], generated by m4_PACKAGE_STRING.
-
-Copyright (C) 2010 Free Software Foundation, Inc.
-This config.lt script is free software; the Free Software Foundation
-gives unlimited permision to copy, distribute and modify it."
-
-while test $[#] != 0
-do
-  case $[1] in
-    --version | --v* | -V )
-      echo "$lt_cl_version"; exit 0 ;;
-    --help | --h* | -h )
-      echo "$lt_cl_help"; exit 0 ;;
-    --debug | --d* | -d )
-      debug=: ;;
-    --quiet | --q* | --silent | --s* | -q )
-      lt_cl_silent=: ;;
-
-    -*) AC_MSG_ERROR([unrecognized option: $[1]
-Try \`$[0] --help' for more information.]) ;;
-
-    *) AC_MSG_ERROR([unrecognized argument: $[1]
-Try \`$[0] --help' for more information.]) ;;
-  esac
-  shift
-done
-
-if $lt_cl_silent; then
-  exec AS_MESSAGE_FD>/dev/null
-fi
-_LTEOF
-
-cat >>"$CONFIG_LT" <<_LTEOF
-_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
-_LTEOF
-
-cat >>"$CONFIG_LT" <<\_LTEOF
-AC_MSG_NOTICE([creating $ofile])
-_LT_OUTPUT_LIBTOOL_COMMANDS
-AS_EXIT(0)
-_LTEOF
-chmod +x "$CONFIG_LT"
-
-# configure is writing to config.log, but config.lt does its own redirection,
-# appending to config.log, which fails on DOS, as config.log is still kept
-# open by configure.  Here we exec the FD to /dev/null, effectively closing
-# config.log, so it can be properly (re)opened and appended to by config.lt.
-lt_cl_success=:
-test "$silent" = yes &&
-  lt_config_lt_args="$lt_config_lt_args --quiet"
-exec AS_MESSAGE_LOG_FD>/dev/null
-$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
-exec AS_MESSAGE_LOG_FD>>config.log
-$lt_cl_success || AS_EXIT(1)
-])# LT_OUTPUT
-
-
-# _LT_CONFIG(TAG)
-# ---------------
-# If TAG is the built-in tag, create an initial libtool script with a
-# default configuration from the untagged config vars.  Otherwise add code
-# to config.status for appending the configuration named by TAG from the
-# matching tagged config vars.
-m4_defun([_LT_CONFIG],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-_LT_CONFIG_SAVE_COMMANDS([
-  m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
-  m4_if(_LT_TAG, [C], [
-    # See if we are running on zsh, and set the options which allow our
-    # commands through without removal of \ escapes.
-    if test -n "${ZSH_VERSION+set}" ; then
-      setopt NO_GLOB_SUBST
-    fi
-
-    cfgfile="${ofile}T"
-    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
-    $RM "$cfgfile"
-
-    cat <<_LT_EOF >> "$cfgfile"
-#! $SHELL
-
-# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
-# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
-# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
-# NOTE: Changes made to this file will be lost: look at ltmain.sh.
-#
-_LT_COPYING
-_LT_LIBTOOL_TAGS
-
-# ### BEGIN LIBTOOL CONFIG
-_LT_LIBTOOL_CONFIG_VARS
-_LT_LIBTOOL_TAG_VARS
-# ### END LIBTOOL CONFIG
-
-_LT_EOF
-
-  case $host_os in
-  aix3*)
-    cat <<\_LT_EOF >> "$cfgfile"
-# AIX sometimes has problems with the GCC collect2 program.  For some
-# reason, if we set the COLLECT_NAMES environment variable, the problems
-# vanish in a puff of smoke.
-if test "X${COLLECT_NAMES+set}" != Xset; then
-  COLLECT_NAMES=
-  export COLLECT_NAMES
-fi
-_LT_EOF
-    ;;
-  esac
-
-  _LT_PROG_LTMAIN
-
-  # We use sed instead of cat because bash on DJGPP gets confused if
-  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
-  # text mode, it properly converts lines to CR/LF.  This bash problem
-  # is reportedly fixed, but why not run on old versions too?
-  sed '$q' "$ltmain" >> "$cfgfile" \
-     || (rm -f "$cfgfile"; exit 1)
-
-  _LT_PROG_REPLACE_SHELLFNS
-
-   mv -f "$cfgfile" "$ofile" ||
-    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
-  chmod +x "$ofile"
-],
-[cat <<_LT_EOF >> "$ofile"
-
-dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
-dnl in a comment (ie after a #).
-# ### BEGIN LIBTOOL TAG CONFIG: $1
-_LT_LIBTOOL_TAG_VARS(_LT_TAG)
-# ### END LIBTOOL TAG CONFIG: $1
-_LT_EOF
-])dnl /m4_if
-],
-[m4_if([$1], [], [
-    PACKAGE='$PACKAGE'
-    VERSION='$VERSION'
-    TIMESTAMP='$TIMESTAMP'
-    RM='$RM'
-    ofile='$ofile'], [])
-])dnl /_LT_CONFIG_SAVE_COMMANDS
-])# _LT_CONFIG
-
-
-# LT_SUPPORTED_TAG(TAG)
-# ---------------------
-# Trace this macro to discover what tags are supported by the libtool
-# --tag option, using:
-#    autoconf --trace 'LT_SUPPORTED_TAG:$1'
-AC_DEFUN([LT_SUPPORTED_TAG], [])
-
-
-# C support is built-in for now
-m4_define([_LT_LANG_C_enabled], [])
-m4_define([_LT_TAGS], [])
-
-
-# LT_LANG(LANG)
-# -------------
-# Enable libtool support for the given language if not already enabled.
-AC_DEFUN([LT_LANG],
-[AC_BEFORE([$0], [LT_OUTPUT])dnl
-m4_case([$1],
-  [C],                 [_LT_LANG(C)],
-  [C++],               [_LT_LANG(CXX)],
-  [Java],              [_LT_LANG(GCJ)],
-  [Fortran 77],                [_LT_LANG(F77)],
-  [Fortran],           [_LT_LANG(FC)],
-  [Windows Resource],  [_LT_LANG(RC)],
-  [m4_ifdef([_LT_LANG_]$1[_CONFIG],
-    [_LT_LANG($1)],
-    [m4_fatal([$0: unsupported language: "$1"])])])dnl
-])# LT_LANG
-
-
-# _LT_LANG(LANGNAME)
-# ------------------
-m4_defun([_LT_LANG],
-[m4_ifdef([_LT_LANG_]$1[_enabled], [],
-  [LT_SUPPORTED_TAG([$1])dnl
-  m4_append([_LT_TAGS], [$1 ])dnl
-  m4_define([_LT_LANG_]$1[_enabled], [])dnl
-  _LT_LANG_$1_CONFIG($1)])dnl
-])# _LT_LANG
-
-
-# _LT_LANG_DEFAULT_CONFIG
-# -----------------------
-m4_defun([_LT_LANG_DEFAULT_CONFIG],
-[AC_PROVIDE_IFELSE([AC_PROG_CXX],
-  [LT_LANG(CXX)],
-  [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
-
-AC_PROVIDE_IFELSE([AC_PROG_F77],
-  [LT_LANG(F77)],
-  [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
-
-AC_PROVIDE_IFELSE([AC_PROG_FC],
-  [LT_LANG(FC)],
-  [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
-
-dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
-dnl pulling things in needlessly.
-AC_PROVIDE_IFELSE([AC_PROG_GCJ],
-  [LT_LANG(GCJ)],
-  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
-    [LT_LANG(GCJ)],
-    [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
-      [LT_LANG(GCJ)],
-      [m4_ifdef([AC_PROG_GCJ],
-       [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
-       m4_ifdef([A][M_PROG_GCJ],
-       [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
-       m4_ifdef([LT_PROG_GCJ],
-       [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
-
-AC_PROVIDE_IFELSE([LT_PROG_RC],
-  [LT_LANG(RC)],
-  [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
-])# _LT_LANG_DEFAULT_CONFIG
-
-# Obsolete macros:
-AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
-AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
-AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
-AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
-AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
-dnl AC_DEFUN([AC_LIBTOOL_F77], [])
-dnl AC_DEFUN([AC_LIBTOOL_FC], [])
-dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
-dnl AC_DEFUN([AC_LIBTOOL_RC], [])
-
-
-# _LT_TAG_COMPILER
-# ----------------
-m4_defun([_LT_TAG_COMPILER],
-[AC_REQUIRE([AC_PROG_CC])dnl
-
-_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
-_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
-_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
-_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
-
-# If no C compiler was specified, use CC.
-LTCC=${LTCC-"$CC"}
-
-# If no C compiler flags were specified, use CFLAGS.
-LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
-
-# Allow CC to be a program name with arguments.
-compiler=$CC
-])# _LT_TAG_COMPILER
-
-
-# _LT_COMPILER_BOILERPLATE
-# ------------------------
-# Check for compiler boilerplate output or warnings with
-# the simple compiler test code.
-m4_defun([_LT_COMPILER_BOILERPLATE],
-[m4_require([_LT_DECL_SED])dnl
-ac_outfile=conftest.$ac_objext
-echo "$lt_simple_compile_test_code" >conftest.$ac_ext
-eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
-_lt_compiler_boilerplate=`cat conftest.err`
-$RM conftest*
-])# _LT_COMPILER_BOILERPLATE
-
-
-# _LT_LINKER_BOILERPLATE
-# ----------------------
-# Check for linker boilerplate output or warnings with
-# the simple link test code.
-m4_defun([_LT_LINKER_BOILERPLATE],
-[m4_require([_LT_DECL_SED])dnl
-ac_outfile=conftest.$ac_objext
-echo "$lt_simple_link_test_code" >conftest.$ac_ext
-eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
-_lt_linker_boilerplate=`cat conftest.err`
-$RM -r conftest*
-])# _LT_LINKER_BOILERPLATE
-
-# _LT_REQUIRED_DARWIN_CHECKS
-# -------------------------
-m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
-  case $host_os in
-    rhapsody* | darwin*)
-    AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
-    AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
-    AC_CHECK_TOOL([LIPO], [lipo], [:])
-    AC_CHECK_TOOL([OTOOL], [otool], [:])
-    AC_CHECK_TOOL([OTOOL64], [otool64], [:])
-    _LT_DECL([], [DSYMUTIL], [1],
-      [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
-    _LT_DECL([], [NMEDIT], [1],
-      [Tool to change global to local symbols on Mac OS X])
-    _LT_DECL([], [LIPO], [1],
-      [Tool to manipulate fat objects and archives on Mac OS X])
-    _LT_DECL([], [OTOOL], [1],
-      [ldd/readelf like tool for Mach-O binaries on Mac OS X])
-    _LT_DECL([], [OTOOL64], [1],
-      [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
-
-    AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
-      [lt_cv_apple_cc_single_mod=no
-      if test -z "${LT_MULTI_MODULE}"; then
-       # By default we will add the -single_module flag. You can override
-       # by either setting the environment variable LT_MULTI_MODULE
-       # non-empty at configure time, or by adding -multi_module to the
-       # link flags.
-       rm -rf libconftest.dylib*
-       echo "int foo(void){return 1;}" > conftest.c
-       echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
--dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
-       $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
-         -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
-        _lt_result=$?
-       if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then
-         lt_cv_apple_cc_single_mod=yes
-       else
-         cat conftest.err >&AS_MESSAGE_LOG_FD
-       fi
-       rm -rf libconftest.dylib*
-       rm -f conftest.*
-      fi])
-    AC_CACHE_CHECK([for -exported_symbols_list linker flag],
-      [lt_cv_ld_exported_symbols_list],
-      [lt_cv_ld_exported_symbols_list=no
-      save_LDFLAGS=$LDFLAGS
-      echo "_main" > conftest.sym
-      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
-      AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
-       [lt_cv_ld_exported_symbols_list=yes],
-       [lt_cv_ld_exported_symbols_list=no])
-       LDFLAGS="$save_LDFLAGS"
-    ])
-    AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
-      [lt_cv_ld_force_load=no
-      cat > conftest.c << _LT_EOF
-int forced_loaded() { return 2;}
-_LT_EOF
-      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
-      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
-      echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
-      $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
-      echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
-      $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
-      cat > conftest.c << _LT_EOF
-int main() { return 0;}
-_LT_EOF
-      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
-      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
-      _lt_result=$?
-      if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then
-       lt_cv_ld_force_load=yes
-      else
-       cat conftest.err >&AS_MESSAGE_LOG_FD
-      fi
-        rm -f conftest.err libconftest.a conftest conftest.c
-        rm -rf conftest.dSYM
-    ])
-    case $host_os in
-    rhapsody* | darwin1.[[012]])
-      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
-    darwin1.*)
-      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
-    darwin*) # darwin 5.x on
-      # if running on 10.5 or later, the deployment target defaults
-      # to the OS version, if on x86, and 10.4, the deployment
-      # target defaults to 10.4. Don't you love it?
-      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
-       10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
-         _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
-       10.[[012]]*)
-         _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
-       10.*)
-         _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
-      esac
-    ;;
-  esac
-    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
-      _lt_dar_single_mod='$single_module'
-    fi
-    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
-      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
-    else
-      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
-    fi
-    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
-      _lt_dsymutil='~$DSYMUTIL $lib || :'
-    else
-      _lt_dsymutil=
-    fi
-    ;;
-  esac
-])
-
-
-# _LT_DARWIN_LINKER_FEATURES
-# --------------------------
-# Checks for linker and compiler features on darwin
-m4_defun([_LT_DARWIN_LINKER_FEATURES],
-[
-  m4_require([_LT_REQUIRED_DARWIN_CHECKS])
-  _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-  _LT_TAGVAR(hardcode_direct, $1)=no
-  _LT_TAGVAR(hardcode_automatic, $1)=yes
-  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
-  if test "$lt_cv_ld_force_load" = "yes"; then
-    _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
-  else
-    _LT_TAGVAR(whole_archive_flag_spec, $1)=''
-  fi
-  _LT_TAGVAR(link_all_deplibs, $1)=yes
-  _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
-  case $cc_basename in
-     ifort*) _lt_dar_can_shared=yes ;;
-     *) _lt_dar_can_shared=$GCC ;;
-  esac
-  if test "$_lt_dar_can_shared" = "yes"; then
-    output_verbose_link_cmd=func_echo_all
-    _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
-    _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
-    _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
-    _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
-    m4_if([$1], [CXX],
-[   if test "$lt_cv_apple_cc_single_mod" != "yes"; then
-      _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
-      _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
-    fi
-],[])
-  else
-  _LT_TAGVAR(ld_shlibs, $1)=no
-  fi
-])
-
-# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
-# ----------------------------------
-# Links a minimal program and checks the executable
-# for the system default hardcoded library path. In most cases,
-# this is /usr/lib:/lib, but when the MPI compilers are used
-# the location of the communication and MPI libs are included too.
-# If we don't find anything, use the default library path according
-# to the aix ld manual.
-# Store the results from the different compilers for each TAGNAME.
-# Allow to override them for all tags through lt_cv_aix_libpath.
-m4_defun([_LT_SYS_MODULE_PATH_AIX],
-[m4_require([_LT_DECL_SED])dnl
-if test "${lt_cv_aix_libpath+set}" = set; then
-  aix_libpath=$lt_cv_aix_libpath
-else
-  AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
-  [AC_LINK_IFELSE([AC_LANG_PROGRAM],[
-  lt_aix_libpath_sed='[
-      /Import File Strings/,/^$/ {
-         /^0/ {
-             s/^0  *\([^ ]*\) *$/\1/
-             p
-         }
-      }]'
-  _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
-  # Check for a 64-bit object if we didn't find anything.
-  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
-    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
-  fi],[])
-  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
-    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib"
-  fi
-  ])
-  aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
-fi
-])# _LT_SYS_MODULE_PATH_AIX
-
-
-# _LT_SHELL_INIT(ARG)
-# -------------------
-m4_define([_LT_SHELL_INIT],
-[m4_divert_text([M4SH-INIT], [$1
-])])# _LT_SHELL_INIT
-
-
-
-# _LT_PROG_ECHO_BACKSLASH
-# -----------------------
-# Find how we can fake an echo command that does not interpret backslash.
-# In particular, with Autoconf 2.60 or later we add some code to the start
-# of the generated configure script which will find a shell with a builtin
-# printf (which we can use as an echo command).
-m4_defun([_LT_PROG_ECHO_BACKSLASH],
-[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
-ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
-
-AC_MSG_CHECKING([how to print strings])
-# Test print first, because it will be a builtin if present.
-if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
-   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
-  ECHO='print -r --'
-elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
-  ECHO='printf %s\n'
-else
-  # Use this function as a fallback that always works.
-  func_fallback_echo ()
-  {
-    eval 'cat <<_LTECHO_EOF
-$[]1
-_LTECHO_EOF'
-  }
-  ECHO='func_fallback_echo'
-fi
-
-# func_echo_all arg...
-# Invoke $ECHO with all args, space-separated.
-func_echo_all ()
-{
-    $ECHO "$*" 
-}
-
-case "$ECHO" in
-  printf*) AC_MSG_RESULT([printf]) ;;
-  print*) AC_MSG_RESULT([print -r]) ;;
-  *) AC_MSG_RESULT([cat]) ;;
-esac
-
-m4_ifdef([_AS_DETECT_SUGGESTED],
-[_AS_DETECT_SUGGESTED([
-  test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
-    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
-    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
-    PATH=/empty FPATH=/empty; export PATH FPATH
-    test "X`printf %s $ECHO`" = "X$ECHO" \
-      || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
-
-_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
-_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
-])# _LT_PROG_ECHO_BACKSLASH
-
-
-# _LT_WITH_SYSROOT
-# ----------------
-AC_DEFUN([_LT_WITH_SYSROOT],
-[AC_MSG_CHECKING([for sysroot])
-AC_ARG_WITH([sysroot],
-[  --with-sysroot[=DIR] Search for dependent libraries within DIR
-                        (or the compiler's sysroot if not specified).],
-[], [with_sysroot=no])
-
-dnl lt_sysroot will always be passed unquoted.  We quote it here
-dnl in case the user passed a directory name.
-lt_sysroot=
-case ${with_sysroot} in #(
- yes)
-   if test "$GCC" = yes; then
-     lt_sysroot=`$CC --print-sysroot 2>/dev/null`
-   fi
-   ;; #(
- /*)
-   lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
-   ;; #(
- no|'')
-   ;; #(
- *)
-   AC_MSG_RESULT([${with_sysroot}])
-   AC_MSG_ERROR([The sysroot must be an absolute path.])
-   ;;
-esac
-
- AC_MSG_RESULT([${lt_sysroot:-no}])
-_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
-[dependent libraries, and in which our libraries should be installed.])])
-
-# _LT_ENABLE_LOCK
-# ---------------
-m4_defun([_LT_ENABLE_LOCK],
-[AC_ARG_ENABLE([libtool-lock],
-  [AS_HELP_STRING([--disable-libtool-lock],
-    [avoid locking (might break parallel builds)])])
-test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
-
-# Some flags need to be propagated to the compiler or linker for good
-# libtool support.
-case $host in
-ia64-*-hpux*)
-  # Find out which ABI we are using.
-  echo 'int i;' > conftest.$ac_ext
-  if AC_TRY_EVAL(ac_compile); then
-    case `/usr/bin/file conftest.$ac_objext` in
-      *ELF-32*)
-       HPUX_IA64_MODE="32"
-       ;;
-      *ELF-64*)
-       HPUX_IA64_MODE="64"
-       ;;
-    esac
-  fi
-  rm -rf conftest*
-  ;;
-*-*-irix6*)
-  # Find out which ABI we are using.
-  echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
-  if AC_TRY_EVAL(ac_compile); then
-    if test "$lt_cv_prog_gnu_ld" = yes; then
-      case `/usr/bin/file conftest.$ac_objext` in
-       *32-bit*)
-         LD="${LD-ld} -melf32bsmip"
-         ;;
-       *N32*)
-         LD="${LD-ld} -melf32bmipn32"
-         ;;
-       *64-bit*)
-         LD="${LD-ld} -melf64bmip"
-       ;;
-      esac
-    else
-      case `/usr/bin/file conftest.$ac_objext` in
-       *32-bit*)
-         LD="${LD-ld} -32"
-         ;;
-       *N32*)
-         LD="${LD-ld} -n32"
-         ;;
-       *64-bit*)
-         LD="${LD-ld} -64"
-         ;;
-      esac
-    fi
-  fi
-  rm -rf conftest*
-  ;;
-
-x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
-s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
-  # Find out which ABI we are using.
-  echo 'int i;' > conftest.$ac_ext
-  if AC_TRY_EVAL(ac_compile); then
-    case `/usr/bin/file conftest.o` in
-      *32-bit*)
-       case $host in
-         x86_64-*kfreebsd*-gnu)
-           LD="${LD-ld} -m elf_i386_fbsd"
-           ;;
-         x86_64-*linux*)
-           LD="${LD-ld} -m elf_i386"
-           ;;
-         ppc64-*linux*|powerpc64-*linux*)
-           LD="${LD-ld} -m elf32ppclinux"
-           ;;
-         s390x-*linux*)
-           LD="${LD-ld} -m elf_s390"
-           ;;
-         sparc64-*linux*)
-           LD="${LD-ld} -m elf32_sparc"
-           ;;
-       esac
-       ;;
-      *64-bit*)
-       case $host in
-         x86_64-*kfreebsd*-gnu)
-           LD="${LD-ld} -m elf_x86_64_fbsd"
-           ;;
-         x86_64-*linux*)
-           LD="${LD-ld} -m elf_x86_64"
-           ;;
-         ppc*-*linux*|powerpc*-*linux*)
-           LD="${LD-ld} -m elf64ppc"
-           ;;
-         s390*-*linux*|s390*-*tpf*)
-           LD="${LD-ld} -m elf64_s390"
-           ;;
-         sparc*-*linux*)
-           LD="${LD-ld} -m elf64_sparc"
-           ;;
-       esac
-       ;;
-    esac
-  fi
-  rm -rf conftest*
-  ;;
-
-*-*-sco3.2v5*)
-  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
-  SAVE_CFLAGS="$CFLAGS"
-  CFLAGS="$CFLAGS -belf"
-  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
-    [AC_LANG_PUSH(C)
-     AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
-     AC_LANG_POP])
-  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
-    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
-    CFLAGS="$SAVE_CFLAGS"
-  fi
-  ;;
-sparc*-*solaris*)
-  # Find out which ABI we are using.
-  echo 'int i;' > conftest.$ac_ext
-  if AC_TRY_EVAL(ac_compile); then
-    case `/usr/bin/file conftest.o` in
-    *64-bit*)
-      case $lt_cv_prog_gnu_ld in
-      yes*) LD="${LD-ld} -m elf64_sparc" ;;
-      *)
-       if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
-         LD="${LD-ld} -64"
-       fi
-       ;;
-      esac
-      ;;
-    esac
-  fi
-  rm -rf conftest*
-  ;;
-esac
-
-need_locks="$enable_libtool_lock"
-])# _LT_ENABLE_LOCK
-
-
-# _LT_PROG_AR
-# -----------
-m4_defun([_LT_PROG_AR],
-[AC_CHECK_TOOLS(AR, [ar], false)
-: ${AR=ar}
-: ${AR_FLAGS=cru}
-_LT_DECL([], [AR], [1], [The archiver])
-_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
-
-AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
-  [lt_cv_ar_at_file=no
-   AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
-     [echo conftest.$ac_objext > conftest.lst
-      lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
-      AC_TRY_EVAL([lt_ar_try])
-      if test "$ac_status" -eq 0; then
-       # Ensure the archiver fails upon bogus file names.
-       rm -f conftest.$ac_objext libconftest.a
-       AC_TRY_EVAL([lt_ar_try])
-       if test "$ac_status" -ne 0; then
-          lt_cv_ar_at_file=@
-        fi
-      fi
-      rm -f conftest.* libconftest.a
-     ])
-  ])
-
-if test "x$lt_cv_ar_at_file" = xno; then
-  archiver_list_spec=
-else
-  archiver_list_spec=$lt_cv_ar_at_file
-fi
-_LT_DECL([], [archiver_list_spec], [1],
-  [How to feed a file listing to the archiver])
-])# _LT_PROG_AR
-
-
-# _LT_CMD_OLD_ARCHIVE
-# -------------------
-m4_defun([_LT_CMD_OLD_ARCHIVE],
-[_LT_PROG_AR
-
-AC_CHECK_TOOL(STRIP, strip, :)
-test -z "$STRIP" && STRIP=:
-_LT_DECL([], [STRIP], [1], [A symbol stripping program])
-
-AC_CHECK_TOOL(RANLIB, ranlib, :)
-test -z "$RANLIB" && RANLIB=:
-_LT_DECL([], [RANLIB], [1],
-    [Commands used to install an old-style archive])
-
-# Determine commands to create old-style static archives.
-old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
-old_postinstall_cmds='chmod 644 $oldlib'
-old_postuninstall_cmds=
-
-if test -n "$RANLIB"; then
-  case $host_os in
-  openbsd*)
-    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
-    ;;
-  *)
-    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
-    ;;
-  esac
-  old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
-fi
-
-case $host_os in
-  darwin*)
-    lock_old_archive_extraction=yes ;;
-  *)
-    lock_old_archive_extraction=no ;;
-esac
-_LT_DECL([], [old_postinstall_cmds], [2])
-_LT_DECL([], [old_postuninstall_cmds], [2])
-_LT_TAGDECL([], [old_archive_cmds], [2],
-    [Commands used to build an old-style archive])
-_LT_DECL([], [lock_old_archive_extraction], [0],
-    [Whether to use a lock for old archive extraction])
-])# _LT_CMD_OLD_ARCHIVE
-
-
-# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
-#              [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
-# ----------------------------------------------------------------
-# Check whether the given compiler option works
-AC_DEFUN([_LT_COMPILER_OPTION],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_SED])dnl
-AC_CACHE_CHECK([$1], [$2],
-  [$2=no
-   m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
-   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-   lt_compiler_flag="$3"
-   # Insert the option either (1) after the last *FLAGS variable, or
-   # (2) before a word containing "conftest.", or (3) at the end.
-   # Note that $ac_compile itself does not contain backslashes and begins
-   # with a dollar sign (not a hyphen), so the echo should work correctly.
-   # The option is referenced via a variable to avoid confusing sed.
-   lt_compile=`echo "$ac_compile" | $SED \
-   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
-   -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
-   (eval "$lt_compile" 2>conftest.err)
-   ac_status=$?
-   cat conftest.err >&AS_MESSAGE_LOG_FD
-   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
-   if (exit $ac_status) && test -s "$ac_outfile"; then
-     # The compiler can only warn and ignore the option if not recognized
-     # So say no if there are warnings other than the usual output.
-     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
-     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
-     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
-       $2=yes
-     fi
-   fi
-   $RM conftest*
-])
-
-if test x"[$]$2" = xyes; then
-    m4_if([$5], , :, [$5])
-else
-    m4_if([$6], , :, [$6])
-fi
-])# _LT_COMPILER_OPTION
-
-# Old name:
-AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
-
-
-# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
-#                  [ACTION-SUCCESS], [ACTION-FAILURE])
-# ----------------------------------------------------
-# Check whether the given linker option works
-AC_DEFUN([_LT_LINKER_OPTION],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_SED])dnl
-AC_CACHE_CHECK([$1], [$2],
-  [$2=no
-   save_LDFLAGS="$LDFLAGS"
-   LDFLAGS="$LDFLAGS $3"
-   echo "$lt_simple_link_test_code" > conftest.$ac_ext
-   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
-     # The linker can only warn and ignore the option if not recognized
-     # So say no if there are warnings
-     if test -s conftest.err; then
-       # Append any errors to the config.log.
-       cat conftest.err 1>&AS_MESSAGE_LOG_FD
-       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
-       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
-       if diff conftest.exp conftest.er2 >/dev/null; then
-         $2=yes
-       fi
-     else
-       $2=yes
-     fi
-   fi
-   $RM -r conftest*
-   LDFLAGS="$save_LDFLAGS"
-])
-
-if test x"[$]$2" = xyes; then
-    m4_if([$4], , :, [$4])
-else
-    m4_if([$5], , :, [$5])
-fi
-])# _LT_LINKER_OPTION
-
-# Old name:
-AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
-
-
-# LT_CMD_MAX_LEN
-#---------------
-AC_DEFUN([LT_CMD_MAX_LEN],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-# find the maximum length of command line arguments
-AC_MSG_CHECKING([the maximum length of command line arguments])
-AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
-  i=0
-  teststring="ABCD"
-
-  case $build_os in
-  msdosdjgpp*)
-    # On DJGPP, this test can blow up pretty badly due to problems in libc
-    # (any single argument exceeding 2000 bytes causes a buffer overrun
-    # during glob expansion).  Even if it were fixed, the result of this
-    # check would be larger than it should be.
-    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
-    ;;
-
-  gnu*)
-    # Under GNU Hurd, this test is not required because there is
-    # no limit to the length of command line arguments.
-    # Libtool will interpret -1 as no limit whatsoever
-    lt_cv_sys_max_cmd_len=-1;
-    ;;
-
-  cygwin* | mingw* | cegcc*)
-    # On Win9x/ME, this test blows up -- it succeeds, but takes
-    # about 5 minutes as the teststring grows exponentially.
-    # Worse, since 9x/ME are not pre-emptively multitasking,
-    # you end up with a "frozen" computer, even though with patience
-    # the test eventually succeeds (with a max line length of 256k).
-    # Instead, let's just punt: use the minimum linelength reported by
-    # all of the supported platforms: 8192 (on NT/2K/XP).
-    lt_cv_sys_max_cmd_len=8192;
-    ;;
-
-  mint*)
-    # On MiNT this can take a long time and run out of memory.
-    lt_cv_sys_max_cmd_len=8192;
-    ;;
-
-  amigaos*)
-    # On AmigaOS with pdksh, this test takes hours, literally.
-    # So we just punt and use a minimum line length of 8192.
-    lt_cv_sys_max_cmd_len=8192;
-    ;;
-
-  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
-    # This has been around since 386BSD, at least.  Likely further.
-    if test -x /sbin/sysctl; then
-      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
-    elif test -x /usr/sbin/sysctl; then
-      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
-    else
-      lt_cv_sys_max_cmd_len=65536      # usable default for all BSDs
-    fi
-    # And add a safety zone
-    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
-    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
-    ;;
-
-  interix*)
-    # We know the value 262144 and hardcode it with a safety zone (like BSD)
-    lt_cv_sys_max_cmd_len=196608
-    ;;
-
-  osf*)
-    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
-    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
-    # nice to cause kernel panics so lets avoid the loop below.
-    # First set a reasonable default.
-    lt_cv_sys_max_cmd_len=16384
-    #
-    if test -x /sbin/sysconfig; then
-      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
-        *1*) lt_cv_sys_max_cmd_len=-1 ;;
-      esac
-    fi
-    ;;
-  sco3.2v5*)
-    lt_cv_sys_max_cmd_len=102400
-    ;;
-  sysv5* | sco5v6* | sysv4.2uw2*)
-    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
-    if test -n "$kargmax"; then
-      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[        ]]//'`
-    else
-      lt_cv_sys_max_cmd_len=32768
-    fi
-    ;;
-  *)
-    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
-    if test -n "$lt_cv_sys_max_cmd_len"; then
-      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
-      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
-    else
-      # Make teststring a little bigger before we do anything with it.
-      # a 1K string should be a reasonable start.
-      for i in 1 2 3 4 5 6 7 8 ; do
-        teststring=$teststring$teststring
-      done
-      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
-      # If test is not a shell built-in, we'll probably end up computing a
-      # maximum length that is only half of the actual maximum length, but
-      # we can't tell.
-      while { test "X"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \
-                = "X$teststring$teststring"; } >/dev/null 2>&1 &&
-             test $i != 17 # 1/2 MB should be enough
-      do
-        i=`expr $i + 1`
-        teststring=$teststring$teststring
-      done
-      # Only check the string length outside the loop.
-      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
-      teststring=
-      # Add a significant safety factor because C++ compilers can tack on
-      # massive amounts of additional arguments before passing them to the
-      # linker.  It appears as though 1/2 is a usable value.
-      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
-    fi
-    ;;
-  esac
-])
-if test -n $lt_cv_sys_max_cmd_len ; then
-  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
-else
-  AC_MSG_RESULT(none)
-fi
-max_cmd_len=$lt_cv_sys_max_cmd_len
-_LT_DECL([], [max_cmd_len], [0],
-    [What is the maximum length of a command?])
-])# LT_CMD_MAX_LEN
-
-# Old name:
-AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
-
-
-# _LT_HEADER_DLFCN
-# ----------------
-m4_defun([_LT_HEADER_DLFCN],
-[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
-])# _LT_HEADER_DLFCN
-
-
-# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
-#                      ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
-# ----------------------------------------------------------------
-m4_defun([_LT_TRY_DLOPEN_SELF],
-[m4_require([_LT_HEADER_DLFCN])dnl
-if test "$cross_compiling" = yes; then :
-  [$4]
-else
-  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
-  lt_status=$lt_dlunknown
-  cat > conftest.$ac_ext <<_LT_EOF
-[#line $LINENO "configure"
-#include "confdefs.h"
-
-#if HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
-#include <stdio.h>
-
-#ifdef RTLD_GLOBAL
-#  define LT_DLGLOBAL          RTLD_GLOBAL
-#else
-#  ifdef DL_GLOBAL
-#    define LT_DLGLOBAL                DL_GLOBAL
-#  else
-#    define LT_DLGLOBAL                0
-#  endif
-#endif
-
-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
-   find out it does not work in some platform. */
-#ifndef LT_DLLAZY_OR_NOW
-#  ifdef RTLD_LAZY
-#    define LT_DLLAZY_OR_NOW           RTLD_LAZY
-#  else
-#    ifdef DL_LAZY
-#      define LT_DLLAZY_OR_NOW         DL_LAZY
-#    else
-#      ifdef RTLD_NOW
-#        define LT_DLLAZY_OR_NOW       RTLD_NOW
-#      else
-#        ifdef DL_NOW
-#          define LT_DLLAZY_OR_NOW     DL_NOW
-#        else
-#          define LT_DLLAZY_OR_NOW     0
-#        endif
-#      endif
-#    endif
-#  endif
-#endif
-
-/* When -fvisbility=hidden is used, assume the code has been annotated
-   correspondingly for the symbols needed.  */
-#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
-int fnord () __attribute__((visibility("default")));
-#endif
-
-int fnord () { return 42; }
-int main ()
-{
-  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
-  int status = $lt_dlunknown;
-
-  if (self)
-    {
-      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
-      else
-        {
-         if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
-          else puts (dlerror ());
-       }
-      /* dlclose (self); */
-    }
-  else
-    puts (dlerror ());
-
-  return status;
-}]
-_LT_EOF
-  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
-    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
-    lt_status=$?
-    case x$lt_status in
-      x$lt_dlno_uscore) $1 ;;
-      x$lt_dlneed_uscore) $2 ;;
-      x$lt_dlunknown|x*) $3 ;;
-    esac
-  else :
-    # compilation failed
-    $3
-  fi
-fi
-rm -fr conftest*
-])# _LT_TRY_DLOPEN_SELF
-
-
-# LT_SYS_DLOPEN_SELF
-# ------------------
-AC_DEFUN([LT_SYS_DLOPEN_SELF],
-[m4_require([_LT_HEADER_DLFCN])dnl
-if test "x$enable_dlopen" != xyes; then
-  enable_dlopen=unknown
-  enable_dlopen_self=unknown
-  enable_dlopen_self_static=unknown
-else
-  lt_cv_dlopen=no
-  lt_cv_dlopen_libs=
-
-  case $host_os in
-  beos*)
-    lt_cv_dlopen="load_add_on"
-    lt_cv_dlopen_libs=
-    lt_cv_dlopen_self=yes
-    ;;
-
-  mingw* | pw32* | cegcc*)
-    lt_cv_dlopen="LoadLibrary"
-    lt_cv_dlopen_libs=
-    ;;
-
-  cygwin*)
-    lt_cv_dlopen="dlopen"
-    lt_cv_dlopen_libs=
-    ;;
-
-  darwin*)
-  # if libdl is installed we need to link against it
-    AC_CHECK_LIB([dl], [dlopen],
-               [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
-    lt_cv_dlopen="dyld"
-    lt_cv_dlopen_libs=
-    lt_cv_dlopen_self=yes
-    ])
-    ;;
-
-  *)
-    AC_CHECK_FUNC([shl_load],
-         [lt_cv_dlopen="shl_load"],
-      [AC_CHECK_LIB([dld], [shl_load],
-           [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
-       [AC_CHECK_FUNC([dlopen],
-             [lt_cv_dlopen="dlopen"],
-         [AC_CHECK_LIB([dl], [dlopen],
-               [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
-           [AC_CHECK_LIB([svld], [dlopen],
-                 [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
-             [AC_CHECK_LIB([dld], [dld_link],
-                   [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
-             ])
-           ])
-         ])
-       ])
-      ])
-    ;;
-  esac
-
-  if test "x$lt_cv_dlopen" != xno; then
-    enable_dlopen=yes
-  else
-    enable_dlopen=no
-  fi
-
-  case $lt_cv_dlopen in
-  dlopen)
-    save_CPPFLAGS="$CPPFLAGS"
-    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
-
-    save_LDFLAGS="$LDFLAGS"
-    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
-
-    save_LIBS="$LIBS"
-    LIBS="$lt_cv_dlopen_libs $LIBS"
-
-    AC_CACHE_CHECK([whether a program can dlopen itself],
-         lt_cv_dlopen_self, [dnl
-         _LT_TRY_DLOPEN_SELF(
-           lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
-           lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
-    ])
-
-    if test "x$lt_cv_dlopen_self" = xyes; then
-      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
-      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
-         lt_cv_dlopen_self_static, [dnl
-         _LT_TRY_DLOPEN_SELF(
-           lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
-           lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
-      ])
-    fi
-
-    CPPFLAGS="$save_CPPFLAGS"
-    LDFLAGS="$save_LDFLAGS"
-    LIBS="$save_LIBS"
-    ;;
-  esac
-
-  case $lt_cv_dlopen_self in
-  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
-  *) enable_dlopen_self=unknown ;;
-  esac
-
-  case $lt_cv_dlopen_self_static in
-  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
-  *) enable_dlopen_self_static=unknown ;;
-  esac
-fi
-_LT_DECL([dlopen_support], [enable_dlopen], [0],
-        [Whether dlopen is supported])
-_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
-        [Whether dlopen of programs is supported])
-_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
-        [Whether dlopen of statically linked programs is supported])
-])# LT_SYS_DLOPEN_SELF
-
-# Old name:
-AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
-
-
-# _LT_COMPILER_C_O([TAGNAME])
-# ---------------------------
-# Check to see if options -c and -o are simultaneously supported by compiler.
-# This macro does not hard code the compiler like AC_PROG_CC_C_O.
-m4_defun([_LT_COMPILER_C_O],
-[m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_TAG_COMPILER])dnl
-AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
-  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
-  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
-   $RM -r conftest 2>/dev/null
-   mkdir conftest
-   cd conftest
-   mkdir out
-   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-
-   lt_compiler_flag="-o out/conftest2.$ac_objext"
-   # Insert the option either (1) after the last *FLAGS variable, or
-   # (2) before a word containing "conftest.", or (3) at the end.
-   # Note that $ac_compile itself does not contain backslashes and begins
-   # with a dollar sign (not a hyphen), so the echo should work correctly.
-   lt_compile=`echo "$ac_compile" | $SED \
-   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
-   -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
-   (eval "$lt_compile" 2>out/conftest.err)
-   ac_status=$?
-   cat out/conftest.err >&AS_MESSAGE_LOG_FD
-   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
-   if (exit $ac_status) && test -s out/conftest2.$ac_objext
-   then
-     # The compiler can only warn and ignore the option if not recognized
-     # So say no if there are warnings
-     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
-     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
-     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
-       _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
-     fi
-   fi
-   chmod u+w . 2>&AS_MESSAGE_LOG_FD
-   $RM conftest*
-   # SGI C++ compiler will create directory out/ii_files/ for
-   # template instantiation
-   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
-   $RM out/* && rmdir out
-   cd ..
-   $RM -r conftest
-   $RM conftest*
-])
-_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
-       [Does compiler simultaneously support -c and -o options?])
-])# _LT_COMPILER_C_O
-
-
-# _LT_COMPILER_FILE_LOCKS([TAGNAME])
-# ----------------------------------
-# Check to see if we can do hard links to lock some files if needed
-m4_defun([_LT_COMPILER_FILE_LOCKS],
-[m4_require([_LT_ENABLE_LOCK])dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-_LT_COMPILER_C_O([$1])
-
-hard_links="nottested"
-if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
-  # do not overwrite the value of need_locks provided by the user
-  AC_MSG_CHECKING([if we can lock with hard links])
-  hard_links=yes
-  $RM conftest*
-  ln conftest.a conftest.b 2>/dev/null && hard_links=no
-  touch conftest.a
-  ln conftest.a conftest.b 2>&5 || hard_links=no
-  ln conftest.a conftest.b 2>/dev/null && hard_links=no
-  AC_MSG_RESULT([$hard_links])
-  if test "$hard_links" = no; then
-    AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
-    need_locks=warn
-  fi
-else
-  need_locks=no
-fi
-_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
-])# _LT_COMPILER_FILE_LOCKS
-
-
-# _LT_CHECK_OBJDIR
-# ----------------
-m4_defun([_LT_CHECK_OBJDIR],
-[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
-[rm -f .libs 2>/dev/null
-mkdir .libs 2>/dev/null
-if test -d .libs; then
-  lt_cv_objdir=.libs
-else
-  # MS-DOS does not allow filenames that begin with a dot.
-  lt_cv_objdir=_libs
-fi
-rmdir .libs 2>/dev/null])
-objdir=$lt_cv_objdir
-_LT_DECL([], [objdir], [0],
-         [The name of the directory that contains temporary libtool files])dnl
-m4_pattern_allow([LT_OBJDIR])dnl
-AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
-  [Define to the sub-directory in which libtool stores uninstalled libraries.])
-])# _LT_CHECK_OBJDIR
-
-
-# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
-# --------------------------------------
-# Check hardcoding attributes.
-m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
-[AC_MSG_CHECKING([how to hardcode library paths into programs])
-_LT_TAGVAR(hardcode_action, $1)=
-if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
-   test -n "$_LT_TAGVAR(runpath_var, $1)" ||
-   test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
-
-  # We can hardcode non-existent directories.
-  if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
-     # If the only mechanism to avoid hardcoding is shlibpath_var, we
-     # have to relink, otherwise we might link with an installed library
-     # when we should be linking with a yet-to-be-installed one
-     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
-     test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
-    # Linking always hardcodes the temporary library directory.
-    _LT_TAGVAR(hardcode_action, $1)=relink
-  else
-    # We can link without hardcoding, and we can hardcode nonexisting dirs.
-    _LT_TAGVAR(hardcode_action, $1)=immediate
-  fi
-else
-  # We cannot hardcode anything, or else we can only hardcode existing
-  # directories.
-  _LT_TAGVAR(hardcode_action, $1)=unsupported
-fi
-AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
-
-if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
-   test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
-  # Fast installation is not supported
-  enable_fast_install=no
-elif test "$shlibpath_overrides_runpath" = yes ||
-     test "$enable_shared" = no; then
-  # Fast installation is not necessary
-  enable_fast_install=needless
-fi
-_LT_TAGDECL([], [hardcode_action], [0],
-    [How to hardcode a shared library path into an executable])
-])# _LT_LINKER_HARDCODE_LIBPATH
-
-
-# _LT_CMD_STRIPLIB
-# ----------------
-m4_defun([_LT_CMD_STRIPLIB],
-[m4_require([_LT_DECL_EGREP])
-striplib=
-old_striplib=
-AC_MSG_CHECKING([whether stripping libraries is possible])
-if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
-  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
-  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
-  AC_MSG_RESULT([yes])
-else
-# FIXME - insert some real tests, host_os isn't really good enough
-  case $host_os in
-  darwin*)
-    if test -n "$STRIP" ; then
-      striplib="$STRIP -x"
-      old_striplib="$STRIP -S"
-      AC_MSG_RESULT([yes])
-    else
-      AC_MSG_RESULT([no])
-    fi
-    ;;
-  *)
-    AC_MSG_RESULT([no])
-    ;;
-  esac
-fi
-_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
-_LT_DECL([], [striplib], [1])
-])# _LT_CMD_STRIPLIB
-
-
-# _LT_SYS_DYNAMIC_LINKER([TAG])
-# -----------------------------
-# PORTME Fill in your ld.so characteristics
-m4_defun([_LT_SYS_DYNAMIC_LINKER],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_OBJDUMP])dnl
-m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_CHECK_SHELL_FEATURES])dnl
-AC_MSG_CHECKING([dynamic linker characteristics])
-m4_if([$1],
-       [], [
-if test "$GCC" = yes; then
-  case $host_os in
-    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
-    *) lt_awk_arg="/^libraries:/" ;;
-  esac
-  case $host_os in
-    mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
-    *) lt_sed_strip_eq="s,=/,/,g" ;;
-  esac
-  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
-  case $lt_search_path_spec in
-  *\;*)
-    # if the path contains ";" then we assume it to be the separator
-    # otherwise default to the standard path separator (i.e. ":") - it is
-    # assumed that no part of a normal pathname contains ";" but that should
-    # okay in the real world where ";" in dirpaths is itself problematic.
-    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
-    ;;
-  *)
-    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
-    ;;
-  esac
-  # Ok, now we have the path, separated by spaces, we can step through it
-  # and add multilib dir if necessary.
-  lt_tmp_lt_search_path_spec=
-  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
-  for lt_sys_path in $lt_search_path_spec; do
-    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
-      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
-    else
-      test -d "$lt_sys_path" && \
-       lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
-    fi
-  done
-  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
-BEGIN {RS=" "; FS="/|\n";} {
-  lt_foo="";
-  lt_count=0;
-  for (lt_i = NF; lt_i > 0; lt_i--) {
-    if ($lt_i != "" && $lt_i != ".") {
-      if ($lt_i == "..") {
-        lt_count++;
-      } else {
-        if (lt_count == 0) {
-          lt_foo="/" $lt_i lt_foo;
-        } else {
-          lt_count--;
-        }
-      }
-    }
-  }
-  if (lt_foo != "") { lt_freq[[lt_foo]]++; }
-  if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
-}'`
-  # AWK program above erroneously prepends '/' to C:/dos/paths
-  # for these hosts.
-  case $host_os in
-    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
-      $SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
-  esac
-  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
-else
-  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
-fi])
-library_names_spec=
-libname_spec='lib$name'
-soname_spec=
-shrext_cmds=".so"
-postinstall_cmds=
-postuninstall_cmds=
-finish_cmds=
-finish_eval=
-shlibpath_var=
-shlibpath_overrides_runpath=unknown
-version_type=none
-dynamic_linker="$host_os ld.so"
-sys_lib_dlsearch_path_spec="/lib /usr/lib"
-need_lib_prefix=unknown
-hardcode_into_libs=no
-
-# when you set need_version to no, make sure it does not cause -set_version
-# flags to be left without arguments
-need_version=unknown
-
-case $host_os in
-aix3*)
-  version_type=linux
-  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
-  shlibpath_var=LIBPATH
-
-  # AIX 3 has no versioning support, so we append a major version to the name.
-  soname_spec='${libname}${release}${shared_ext}$major'
-  ;;
-
-aix[[4-9]]*)
-  version_type=linux
-  need_lib_prefix=no
-  need_version=no
-  hardcode_into_libs=yes
-  if test "$host_cpu" = ia64; then
-    # AIX 5 supports IA64
-    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
-    shlibpath_var=LD_LIBRARY_PATH
-  else
-    # With GCC up to 2.95.x, collect2 would create an import file
-    # for dependence libraries.  The import file would start with
-    # the line `#! .'.  This would cause the generated library to
-    # depend on `.', always an invalid library.  This was fixed in
-    # development snapshots of GCC prior to 3.0.
-    case $host_os in
-      aix4 | aix4.[[01]] | aix4.[[01]].*)
-      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
-          echo ' yes '
-          echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
-       :
-      else
-       can_build_shared=no
-      fi
-      ;;
-    esac
-    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
-    # soname into executable. Probably we can add versioning support to
-    # collect2, so additional links can be useful in future.
-    if test "$aix_use_runtimelinking" = yes; then
-      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
-      # instead of lib<name>.a to let people know that these are not
-      # typical AIX shared libraries.
-      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    else
-      # We preserve .a as extension for shared libraries through AIX4.2
-      # and later when we are not doing run time linking.
-      library_names_spec='${libname}${release}.a $libname.a'
-      soname_spec='${libname}${release}${shared_ext}$major'
-    fi
-    shlibpath_var=LIBPATH
-  fi
-  ;;
-
-amigaos*)
-  case $host_cpu in
-  powerpc)
-    # Since July 2007 AmigaOS4 officially supports .so libraries.
-    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    ;;
-  m68k)
-    library_names_spec='$libname.ixlibrary $libname.a'
-    # Create ${libname}_ixlibrary.a entries in /sys/libs.
-    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
-    ;;
-  esac
-  ;;
-
-beos*)
-  library_names_spec='${libname}${shared_ext}'
-  dynamic_linker="$host_os ld.so"
-  shlibpath_var=LIBRARY_PATH
-  ;;
-
-bsdi[[45]]*)
-  version_type=linux
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
-  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
-  # the default ld.so.conf also contains /usr/contrib/lib and
-  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
-  # libtool to hard-code these into programs
-  ;;
-
-cygwin* | mingw* | pw32* | cegcc*)
-  version_type=windows
-  shrext_cmds=".dll"
-  need_version=no
-  need_lib_prefix=no
-
-  case $GCC,$cc_basename in
-  yes,*)
-    # gcc
-    library_names_spec='$libname.dll.a'
-    # DLL is installed to $(libdir)/../bin by postinstall_cmds
-    postinstall_cmds='base_file=`basename \${file}`~
-      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
-      dldir=$destdir/`dirname \$dlpath`~
-      test -d \$dldir || mkdir -p \$dldir~
-      $install_prog $dir/$dlname \$dldir/$dlname~
-      chmod a+x \$dldir/$dlname~
-      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
-        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
-      fi'
-    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
-      dlpath=$dir/\$dldll~
-       $RM \$dlpath'
-    shlibpath_overrides_runpath=yes
-
-    case $host_os in
-    cygwin*)
-      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
-      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
-m4_if([$1], [],[
-      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
-      ;;
-    mingw* | cegcc*)
-      # MinGW DLLs use traditional 'lib' prefix
-      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
-      ;;
-    pw32*)
-      # pw32 DLLs use 'pw' prefix rather than 'lib'
-      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
-      ;;
-    esac
-    dynamic_linker='Win32 ld.exe'
-    ;;
-
-  *,cl*)
-    # Native MSVC
-    libname_spec='$name'
-    soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
-    library_names_spec='${libname}.dll.lib'
-
-    case $build_os in
-    mingw*)
-      sys_lib_search_path_spec=
-      lt_save_ifs=$IFS
-      IFS=';'
-      for lt_path in $LIB
-      do
-        IFS=$lt_save_ifs
-        # Let DOS variable expansion print the short 8.3 style file name.
-        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
-        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
-      done
-      IFS=$lt_save_ifs
-      # Convert to MSYS style.
-      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
-      ;;
-    cygwin*)
-      # Convert to unix form, then to dos form, then back to unix form
-      # but this time dos style (no spaces!) so that the unix form looks
-      # like /cygdrive/c/PROGRA~1:/cygdr...
-      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
-      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
-      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
-      ;;
-    *)
-      sys_lib_search_path_spec="$LIB"
-      if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
-        # It is most probably a Windows format PATH.
-        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
-      else
-        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
-      fi
-      # FIXME: find the short name or the path components, as spaces are
-      # common. (e.g. "Program Files" -> "PROGRA~1")
-      ;;
-    esac
-
-    # DLL is installed to $(libdir)/../bin by postinstall_cmds
-    postinstall_cmds='base_file=`basename \${file}`~
-      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
-      dldir=$destdir/`dirname \$dlpath`~
-      test -d \$dldir || mkdir -p \$dldir~
-      $install_prog $dir/$dlname \$dldir/$dlname'
-    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
-      dlpath=$dir/\$dldll~
-       $RM \$dlpath'
-    shlibpath_overrides_runpath=yes
-    dynamic_linker='Win32 link.exe'
-    ;;
-
-  *)
-    # Assume MSVC wrapper
-    library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
-    dynamic_linker='Win32 ld.exe'
-    ;;
-  esac
-  # FIXME: first we should search . and the directory the executable is in
-  shlibpath_var=PATH
-  ;;
-
-darwin* | rhapsody*)
-  dynamic_linker="$host_os dyld"
-  version_type=darwin
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
-  soname_spec='${libname}${release}${major}$shared_ext'
-  shlibpath_overrides_runpath=yes
-  shlibpath_var=DYLD_LIBRARY_PATH
-  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
-m4_if([$1], [],[
-  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
-  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
-  ;;
-
-dgux*)
-  version_type=linux
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  ;;
-
-freebsd1*)
-  dynamic_linker=no
-  ;;
-
-freebsd* | dragonfly*)
-  # DragonFly does not have aout.  When/if they implement a new
-  # versioning mechanism, adjust this.
-  if test -x /usr/bin/objformat; then
-    objformat=`/usr/bin/objformat`
-  else
-    case $host_os in
-    freebsd[[123]]*) objformat=aout ;;
-    *) objformat=elf ;;
-    esac
-  fi
-  version_type=freebsd-$objformat
-  case $version_type in
-    freebsd-elf*)
-      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
-      need_version=no
-      need_lib_prefix=no
-      ;;
-    freebsd-*)
-      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
-      need_version=yes
-      ;;
-  esac
-  shlibpath_var=LD_LIBRARY_PATH
-  case $host_os in
-  freebsd2*)
-    shlibpath_overrides_runpath=yes
-    ;;
-  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
-    shlibpath_overrides_runpath=yes
-    hardcode_into_libs=yes
-    ;;
-  freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
-  freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
-    shlibpath_overrides_runpath=no
-    hardcode_into_libs=yes
-    ;;
-  *) # from 4.6 on, and DragonFly
-    shlibpath_overrides_runpath=yes
-    hardcode_into_libs=yes
-    ;;
-  esac
-  ;;
-
-gnu*)
-  version_type=linux
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  hardcode_into_libs=yes
-  ;;
-
-haiku*)
-  version_type=linux
-  need_lib_prefix=no
-  need_version=no
-  dynamic_linker="$host_os runtime_loader"
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
-  hardcode_into_libs=yes
-  ;;
-
-hpux9* | hpux10* | hpux11*)
-  # Give a soname corresponding to the major version so that dld.sl refuses to
-  # link against other versions.
-  version_type=sunos
-  need_lib_prefix=no
-  need_version=no
-  case $host_cpu in
-  ia64*)
-    shrext_cmds='.so'
-    hardcode_into_libs=yes
-    dynamic_linker="$host_os dld.so"
-    shlibpath_var=LD_LIBRARY_PATH
-    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    soname_spec='${libname}${release}${shared_ext}$major'
-    if test "X$HPUX_IA64_MODE" = X32; then
-      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
-    else
-      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
-    fi
-    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
-    ;;
-  hppa*64*)
-    shrext_cmds='.sl'
-    hardcode_into_libs=yes
-    dynamic_linker="$host_os dld.sl"
-    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
-    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    soname_spec='${libname}${release}${shared_ext}$major'
-    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
-    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
-    ;;
-  *)
-    shrext_cmds='.sl'
-    dynamic_linker="$host_os dld.sl"
-    shlibpath_var=SHLIB_PATH
-    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    soname_spec='${libname}${release}${shared_ext}$major'
-    ;;
-  esac
-  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
-  postinstall_cmds='chmod 555 $lib'
-  # or fails outright, so override atomically:
-  install_override_mode=555
-  ;;
-
-interix[[3-9]]*)
-  version_type=linux
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  hardcode_into_libs=yes
-  ;;
-
-irix5* | irix6* | nonstopux*)
-  case $host_os in
-    nonstopux*) version_type=nonstopux ;;
-    *)
-       if test "$lt_cv_prog_gnu_ld" = yes; then
-               version_type=linux
-       else
-               version_type=irix
-       fi ;;
-  esac
-  need_lib_prefix=no
-  need_version=no
-  soname_spec='${libname}${release}${shared_ext}$major'
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
-  case $host_os in
-  irix5* | nonstopux*)
-    libsuff= shlibsuff=
-    ;;
-  *)
-    case $LD in # libtool.m4 will add one of these switches to LD
-    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
-      libsuff= shlibsuff= libmagic=32-bit;;
-    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
-      libsuff=32 shlibsuff=N32 libmagic=N32;;
-    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
-      libsuff=64 shlibsuff=64 libmagic=64-bit;;
-    *) libsuff= shlibsuff= libmagic=never-match;;
-    esac
-    ;;
-  esac
-  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
-  shlibpath_overrides_runpath=no
-  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
-  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
-  hardcode_into_libs=yes
-  ;;
-
-# No shared lib support for Linux oldld, aout, or coff.
-linux*oldld* | linux*aout* | linux*coff*)
-  dynamic_linker=no
-  ;;
-
-# This must be Linux ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu)
-  version_type=linux
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-
-  # Some binutils ld are patched to set DT_RUNPATH
-  AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
-    [lt_cv_shlibpath_overrides_runpath=no
-    save_LDFLAGS=$LDFLAGS
-    save_libdir=$libdir
-    eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
-        LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
-    AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
-      [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
-        [lt_cv_shlibpath_overrides_runpath=yes])])
-    LDFLAGS=$save_LDFLAGS
-    libdir=$save_libdir
-    ])
-  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
-
-  # This implies no fast_install, which is unacceptable.
-  # Some rework will be needed to allow for fast_install
-  # before this can be enabled.
-  hardcode_into_libs=yes
-
-  # Append ld.so.conf contents to the search path
-  if test -f /etc/ld.so.conf; then
-    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[  ]*hwcap[        ]/d;s/[:,      ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
-    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
-  fi
-
-  # We used to test for /lib/ld.so.1 and disable shared libraries on
-  # powerpc, because MkLinux only supported shared libraries with the
-  # GNU dynamic linker.  Since this was broken with cross compilers,
-  # most powerpc-linux boxes support dynamic linking these days and
-  # people can always --disable-shared, the test was removed, and we
-  # assume the GNU/Linux dynamic linker is in use.
-  dynamic_linker='GNU/Linux ld.so'
-  ;;
-
-netbsd*)
-  version_type=sunos
-  need_lib_prefix=no
-  need_version=no
-  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
-    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
-    dynamic_linker='NetBSD (a.out) ld.so'
-  else
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
-    soname_spec='${libname}${release}${shared_ext}$major'
-    dynamic_linker='NetBSD ld.elf_so'
-  fi
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  hardcode_into_libs=yes
-  ;;
-
-newsos6)
-  version_type=linux
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  ;;
-
-*nto* | *qnx*)
-  version_type=qnx
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  hardcode_into_libs=yes
-  dynamic_linker='ldqnx.so'
-  ;;
-
-openbsd*)
-  version_type=sunos
-  sys_lib_dlsearch_path_spec="/usr/lib"
-  need_lib_prefix=no
-  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
-  case $host_os in
-    openbsd3.3 | openbsd3.3.*) need_version=yes ;;
-    *)                         need_version=no  ;;
-  esac
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
-  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
-    case $host_os in
-      openbsd2.[[89]] | openbsd2.[[89]].*)
-       shlibpath_overrides_runpath=no
-       ;;
-      *)
-       shlibpath_overrides_runpath=yes
-       ;;
-      esac
-  else
-    shlibpath_overrides_runpath=yes
-  fi
-  ;;
-
-os2*)
-  libname_spec='$name'
-  shrext_cmds=".dll"
-  need_lib_prefix=no
-  library_names_spec='$libname${shared_ext} $libname.a'
-  dynamic_linker='OS/2 ld.exe'
-  shlibpath_var=LIBPATH
-  ;;
-
-osf3* | osf4* | osf5*)
-  version_type=osf
-  need_lib_prefix=no
-  need_version=no
-  soname_spec='${libname}${release}${shared_ext}$major'
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  shlibpath_var=LD_LIBRARY_PATH
-  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
-  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
-  ;;
-
-rdos*)
-  dynamic_linker=no
-  ;;
-
-solaris*)
-  version_type=linux
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  hardcode_into_libs=yes
-  # ldd complains unless libraries are executable
-  postinstall_cmds='chmod +x $lib'
-  ;;
-
-sunos4*)
-  version_type=sunos
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
-  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  if test "$with_gnu_ld" = yes; then
-    need_lib_prefix=no
-  fi
-  need_version=yes
-  ;;
-
-sysv4 | sysv4.3*)
-  version_type=linux
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  case $host_vendor in
-    sni)
-      shlibpath_overrides_runpath=no
-      need_lib_prefix=no
-      runpath_var=LD_RUN_PATH
-      ;;
-    siemens)
-      need_lib_prefix=no
-      ;;
-    motorola)
-      need_lib_prefix=no
-      need_version=no
-      shlibpath_overrides_runpath=no
-      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
-      ;;
-  esac
-  ;;
-
-sysv4*MP*)
-  if test -d /usr/nec ;then
-    version_type=linux
-    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
-    soname_spec='$libname${shared_ext}.$major'
-    shlibpath_var=LD_LIBRARY_PATH
-  fi
-  ;;
-
-sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
-  version_type=freebsd-elf
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  hardcode_into_libs=yes
-  if test "$with_gnu_ld" = yes; then
-    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
-  else
-    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
-    case $host_os in
-      sco3.2v5*)
-        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
-       ;;
-    esac
-  fi
-  sys_lib_dlsearch_path_spec='/usr/lib'
-  ;;
-
-tpf*)
-  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
-  version_type=linux
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  hardcode_into_libs=yes
-  ;;
-
-uts4*)
-  version_type=linux
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  ;;
-
-*)
-  dynamic_linker=no
-  ;;
-esac
-AC_MSG_RESULT([$dynamic_linker])
-test "$dynamic_linker" = no && can_build_shared=no
-
-variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test "$GCC" = yes; then
-  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
-fi
-
-if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
-  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
-fi
-if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
-  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
-fi
-
-_LT_DECL([], [variables_saved_for_relink], [1],
-    [Variables whose values should be saved in libtool wrapper scripts and
-    restored at link time])
-_LT_DECL([], [need_lib_prefix], [0],
-    [Do we need the "lib" prefix for modules?])
-_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
-_LT_DECL([], [version_type], [0], [Library versioning type])
-_LT_DECL([], [runpath_var], [0],  [Shared library runtime path variable])
-_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
-_LT_DECL([], [shlibpath_overrides_runpath], [0],
-    [Is shlibpath searched before the hard-coded library search path?])
-_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
-_LT_DECL([], [library_names_spec], [1],
-    [[List of archive names.  First name is the real one, the rest are links.
-    The last name is the one that the linker finds with -lNAME]])
-_LT_DECL([], [soname_spec], [1],
-    [[The coded name of the library, if different from the real name]])
-_LT_DECL([], [install_override_mode], [1],
-    [Permission mode override for installation of shared libraries])
-_LT_DECL([], [postinstall_cmds], [2],
-    [Command to use after installation of a shared archive])
-_LT_DECL([], [postuninstall_cmds], [2],
-    [Command to use after uninstallation of a shared archive])
-_LT_DECL([], [finish_cmds], [2],
-    [Commands used to finish a libtool library installation in a directory])
-_LT_DECL([], [finish_eval], [1],
-    [[As "finish_cmds", except a single script fragment to be evaled but
-    not shown]])
-_LT_DECL([], [hardcode_into_libs], [0],
-    [Whether we should hardcode library paths into libraries])
-_LT_DECL([], [sys_lib_search_path_spec], [2],
-    [Compile-time system search path for libraries])
-_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
-    [Run-time system search path for libraries])
-])# _LT_SYS_DYNAMIC_LINKER
-
-
-# _LT_PATH_TOOL_PREFIX(TOOL)
-# --------------------------
-# find a file program which can recognize shared library
-AC_DEFUN([_LT_PATH_TOOL_PREFIX],
-[m4_require([_LT_DECL_EGREP])dnl
-AC_MSG_CHECKING([for $1])
-AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
-[case $MAGIC_CMD in
-[[\\/*] |  ?:[\\/]*])
-  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
-  ;;
-*)
-  lt_save_MAGIC_CMD="$MAGIC_CMD"
-  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
-dnl $ac_dummy forces splitting on constant user-supplied paths.
-dnl POSIX.2 word splitting is done only on the output of word expansions,
-dnl not every word.  This closes a longstanding sh security hole.
-  ac_dummy="m4_if([$2], , $PATH, [$2])"
-  for ac_dir in $ac_dummy; do
-    IFS="$lt_save_ifs"
-    test -z "$ac_dir" && ac_dir=.
-    if test -f $ac_dir/$1; then
-      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
-      if test -n "$file_magic_test_file"; then
-       case $deplibs_check_method in
-       "file_magic "*)
-         file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
-         MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
-         if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
-           $EGREP "$file_magic_regex" > /dev/null; then
-           :
-         else
-           cat <<_LT_EOF 1>&2
-
-*** Warning: the command libtool uses to detect shared libraries,
-*** $file_magic_cmd, produces output that libtool cannot recognize.
-*** The result is that libtool may fail to recognize shared libraries
-*** as such.  This will affect the creation of libtool libraries that
-*** depend on shared libraries, but programs linked with such libtool
-*** libraries will work regardless of this problem.  Nevertheless, you
-*** may want to report the problem to your system manager and/or to
-*** bug-libtool@gnu.org
-
-_LT_EOF
-         fi ;;
-       esac
-      fi
-      break
-    fi
-  done
-  IFS="$lt_save_ifs"
-  MAGIC_CMD="$lt_save_MAGIC_CMD"
-  ;;
-esac])
-MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
-if test -n "$MAGIC_CMD"; then
-  AC_MSG_RESULT($MAGIC_CMD)
-else
-  AC_MSG_RESULT(no)
-fi
-_LT_DECL([], [MAGIC_CMD], [0],
-        [Used to examine libraries when file_magic_cmd begins with "file"])dnl
-])# _LT_PATH_TOOL_PREFIX
-
-# Old name:
-AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
-
-
-# _LT_PATH_MAGIC
-# --------------
-# find a file program which can recognize a shared library
-m4_defun([_LT_PATH_MAGIC],
-[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
-if test -z "$lt_cv_path_MAGIC_CMD"; then
-  if test -n "$ac_tool_prefix"; then
-    _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
-  else
-    MAGIC_CMD=:
-  fi
-fi
-])# _LT_PATH_MAGIC
-
-
-# LT_PATH_LD
-# ----------
-# find the pathname to the GNU or non-GNU linker
-AC_DEFUN([LT_PATH_LD],
-[AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
-
-AC_ARG_WITH([gnu-ld],
-    [AS_HELP_STRING([--with-gnu-ld],
-       [assume the C compiler uses GNU ld @<:@default=no@:>@])],
-    [test "$withval" = no || with_gnu_ld=yes],
-    [with_gnu_ld=no])dnl
-
-ac_prog=ld
-if test "$GCC" = yes; then
-  # Check if gcc -print-prog-name=ld gives a path.
-  AC_MSG_CHECKING([for ld used by $CC])
-  case $host in
-  *-*-mingw*)
-    # gcc leaves a trailing carriage return which upsets mingw
-    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
-  *)
-    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
-  esac
-  case $ac_prog in
-    # Accept absolute paths.
-    [[\\/]]* | ?:[[\\/]]*)
-      re_direlt='/[[^/]][[^/]]*/\.\./'
-      # Canonicalize the pathname of ld
-      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
-      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
-       ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
-      done
-      test -z "$LD" && LD="$ac_prog"
-      ;;
-  "")
-    # If it fails, then pretend we aren't using GCC.
-    ac_prog=ld
-    ;;
-  *)
-    # If it is relative, then search for the first ld in PATH.
-    with_gnu_ld=unknown
-    ;;
-  esac
-elif test "$with_gnu_ld" = yes; then
-  AC_MSG_CHECKING([for GNU ld])
-else
-  AC_MSG_CHECKING([for non-GNU ld])
-fi
-AC_CACHE_VAL(lt_cv_path_LD,
-[if test -z "$LD"; then
-  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
-  for ac_dir in $PATH; do
-    IFS="$lt_save_ifs"
-    test -z "$ac_dir" && ac_dir=.
-    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
-      lt_cv_path_LD="$ac_dir/$ac_prog"
-      # Check to see if the program is GNU ld.  I'd rather use --version,
-      # but apparently some variants of GNU ld only accept -v.
-      # Break only if it was the GNU/non-GNU ld that we prefer.
-      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
-      *GNU* | *'with BFD'*)
-       test "$with_gnu_ld" != no && break
-       ;;
-      *)
-       test "$with_gnu_ld" != yes && break
-       ;;
-      esac
-    fi
-  done
-  IFS="$lt_save_ifs"
-else
-  lt_cv_path_LD="$LD" # Let the user override the test with a path.
-fi])
-LD="$lt_cv_path_LD"
-if test -n "$LD"; then
-  AC_MSG_RESULT($LD)
-else
-  AC_MSG_RESULT(no)
-fi
-test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
-_LT_PATH_LD_GNU
-AC_SUBST([LD])
-
-_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
-])# LT_PATH_LD
-
-# Old names:
-AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
-AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AM_PROG_LD], [])
-dnl AC_DEFUN([AC_PROG_LD], [])
-
-
-# _LT_PATH_LD_GNU
-#- --------------
-m4_defun([_LT_PATH_LD_GNU],
-[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
-[# I'd rather use --version here, but apparently some GNU lds only accept -v.
-case `$LD -v 2>&1 </dev/null` in
-*GNU* | *'with BFD'*)
-  lt_cv_prog_gnu_ld=yes
-  ;;
-*)
-  lt_cv_prog_gnu_ld=no
-  ;;
-esac])
-with_gnu_ld=$lt_cv_prog_gnu_ld
-])# _LT_PATH_LD_GNU
-
-
-# _LT_CMD_RELOAD
-# --------------
-# find reload flag for linker
-#   -- PORTME Some linkers may need a different reload flag.
-m4_defun([_LT_CMD_RELOAD],
-[AC_CACHE_CHECK([for $LD option to reload object files],
-  lt_cv_ld_reload_flag,
-  [lt_cv_ld_reload_flag='-r'])
-reload_flag=$lt_cv_ld_reload_flag
-case $reload_flag in
-"" | " "*) ;;
-*) reload_flag=" $reload_flag" ;;
-esac
-reload_cmds='$LD$reload_flag -o $output$reload_objs'
-case $host_os in
-  cygwin* | mingw* | pw32* | cegcc*)
-    if test "$GCC" != yes; then
-      reload_cmds=false
-    fi
-    ;;
-  darwin*)
-    if test "$GCC" = yes; then
-      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
-    else
-      reload_cmds='$LD$reload_flag -o $output$reload_objs'
-    fi
-    ;;
-esac
-_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
-_LT_TAGDECL([], [reload_cmds], [2])dnl
-])# _LT_CMD_RELOAD
-
-
-# _LT_CHECK_MAGIC_METHOD
-# ----------------------
-# how to check for library dependencies
-#  -- PORTME fill in with the dynamic library characteristics
-m4_defun([_LT_CHECK_MAGIC_METHOD],
-[m4_require([_LT_DECL_EGREP])
-m4_require([_LT_DECL_OBJDUMP])
-AC_CACHE_CHECK([how to recognize dependent libraries],
-lt_cv_deplibs_check_method,
-[lt_cv_file_magic_cmd='$MAGIC_CMD'
-lt_cv_file_magic_test_file=
-lt_cv_deplibs_check_method='unknown'
-# Need to set the preceding variable on all platforms that support
-# interlibrary dependencies.
-# 'none' -- dependencies not supported.
-# `unknown' -- same as none, but documents that we really don't know.
-# 'pass_all' -- all dependencies passed with no checks.
-# 'test_compile' -- check by making test program.
-# 'file_magic [[regex]]' -- check by looking for files in library path
-# which responds to the $file_magic_cmd with a given extended regex.
-# If you have `file' or equivalent on your system and you're not sure
-# whether `pass_all' will *always* work, you probably want this one.
-
-case $host_os in
-aix[[4-9]]*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-beos*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-bsdi[[45]]*)
-  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
-  lt_cv_file_magic_cmd='/usr/bin/file -L'
-  lt_cv_file_magic_test_file=/shlib/libc.so
-  ;;
-
-cygwin*)
-  # func_win32_libid is a shell function defined in ltmain.sh
-  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
-  lt_cv_file_magic_cmd='func_win32_libid'
-  ;;
-
-mingw* | pw32*)
-  # Base MSYS/MinGW do not provide the 'file' command needed by
-  # func_win32_libid shell function, so use a weaker test based on 'objdump',
-  # unless we find 'file', for example because we are cross-compiling.
-  # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
-  if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
-    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
-    lt_cv_file_magic_cmd='func_win32_libid'
-  else
-    # Keep this pattern in sync with the one in func_win32_libid.
-    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
-    lt_cv_file_magic_cmd='$OBJDUMP -f'
-  fi
-  ;;
-
-cegcc*)
-  # use the weaker test based on 'objdump'. See mingw*.
-  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
-  lt_cv_file_magic_cmd='$OBJDUMP -f'
-  ;;
-
-darwin* | rhapsody*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-freebsd* | dragonfly*)
-  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
-    case $host_cpu in
-    i*86 )
-      # Not sure whether the presence of OpenBSD here was a mistake.
-      # Let's accept both of them until this is cleared up.
-      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
-      lt_cv_file_magic_cmd=/usr/bin/file
-      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
-      ;;
-    esac
-  else
-    lt_cv_deplibs_check_method=pass_all
-  fi
-  ;;
-
-gnu*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-haiku*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-hpux10.20* | hpux11*)
-  lt_cv_file_magic_cmd=/usr/bin/file
-  case $host_cpu in
-  ia64*)
-    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
-    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
-    ;;
-  hppa*64*)
-    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
-    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
-    ;;
-  *)
-    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
-    lt_cv_file_magic_test_file=/usr/lib/libc.sl
-    ;;
-  esac
-  ;;
-
-interix[[3-9]]*)
-  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
-  lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
-  ;;
-
-irix5* | irix6* | nonstopux*)
-  case $LD in
-  *-32|*"-32 ") libmagic=32-bit;;
-  *-n32|*"-n32 ") libmagic=N32;;
-  *-64|*"-64 ") libmagic=64-bit;;
-  *) libmagic=never-match;;
-  esac
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-# This must be Linux ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-netbsd*)
-  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
-    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
-  else
-    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
-  fi
-  ;;
-
-newos6*)
-  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
-  lt_cv_file_magic_cmd=/usr/bin/file
-  lt_cv_file_magic_test_file=/usr/lib/libnls.so
-  ;;
-
-*nto* | *qnx*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-openbsd*)
-  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
-    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
-  else
-    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
-  fi
-  ;;
-
-osf3* | osf4* | osf5*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-rdos*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-solaris*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-sysv4 | sysv4.3*)
-  case $host_vendor in
-  motorola)
-    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
-    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
-    ;;
-  ncr)
-    lt_cv_deplibs_check_method=pass_all
-    ;;
-  sequent)
-    lt_cv_file_magic_cmd='/bin/file'
-    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
-    ;;
-  sni)
-    lt_cv_file_magic_cmd='/bin/file'
-    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
-    lt_cv_file_magic_test_file=/lib/libc.so
-    ;;
-  siemens)
-    lt_cv_deplibs_check_method=pass_all
-    ;;
-  pc)
-    lt_cv_deplibs_check_method=pass_all
-    ;;
-  esac
-  ;;
-
-tpf*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-esac
-])
-
-file_magic_glob=
-want_nocaseglob=no
-if test "$build" = "$host"; then
-  case $host_os in
-  mingw* | pw32*)
-    if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
-      want_nocaseglob=yes
-    else
-      file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
-    fi
-    ;;
-  esac
-fi
-
-file_magic_cmd=$lt_cv_file_magic_cmd
-deplibs_check_method=$lt_cv_deplibs_check_method
-test -z "$deplibs_check_method" && deplibs_check_method=unknown
-
-_LT_DECL([], [deplibs_check_method], [1],
-    [Method to check whether dependent libraries are shared objects])
-_LT_DECL([], [file_magic_cmd], [1],
-    [Command to use when deplibs_check_method = "file_magic"])
-_LT_DECL([], [file_magic_glob], [1],
-    [How to find potential files when deplibs_check_method = "file_magic"])
-_LT_DECL([], [want_nocaseglob], [1],
-    [Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
-])# _LT_CHECK_MAGIC_METHOD
-
-
-# LT_PATH_NM
-# ----------
-# find the pathname to a BSD- or MS-compatible name lister
-AC_DEFUN([LT_PATH_NM],
-[AC_REQUIRE([AC_PROG_CC])dnl
-AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
-[if test -n "$NM"; then
-  # Let the user override the test.
-  lt_cv_path_NM="$NM"
-else
-  lt_nm_to_check="${ac_tool_prefix}nm"
-  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
-    lt_nm_to_check="$lt_nm_to_check nm"
-  fi
-  for lt_tmp_nm in $lt_nm_to_check; do
-    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
-    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
-      IFS="$lt_save_ifs"
-      test -z "$ac_dir" && ac_dir=.
-      tmp_nm="$ac_dir/$lt_tmp_nm"
-      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
-       # Check to see if the nm accepts a BSD-compat flag.
-       # Adding the `sed 1q' prevents false positives on HP-UX, which says:
-       #   nm: unknown option "B" ignored
-       # Tru64's nm complains that /dev/null is an invalid object file
-       case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
-       */dev/null* | *'Invalid file or object type'*)
-         lt_cv_path_NM="$tmp_nm -B"
-         break
-         ;;
-       *)
-         case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
-         */dev/null*)
-           lt_cv_path_NM="$tmp_nm -p"
-           break
-           ;;
-         *)
-           lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
-           continue # so that we can try to find one that supports BSD flags
-           ;;
-         esac
-         ;;
-       esac
-      fi
-    done
-    IFS="$lt_save_ifs"
-  done
-  : ${lt_cv_path_NM=no}
-fi])
-if test "$lt_cv_path_NM" != "no"; then
-  NM="$lt_cv_path_NM"
-else
-  # Didn't find any BSD compatible name lister, look for dumpbin.
-  if test -n "$DUMPBIN"; then :
-    # Let the user override the test.
-  else
-    AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
-    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
-    *COFF*)
-      DUMPBIN="$DUMPBIN -symbols"
-      ;;
-    *)
-      DUMPBIN=:
-      ;;
-    esac
-  fi
-  AC_SUBST([DUMPBIN])
-  if test "$DUMPBIN" != ":"; then
-    NM="$DUMPBIN"
-  fi
-fi
-test -z "$NM" && NM=nm
-AC_SUBST([NM])
-_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
-
-AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
-  [lt_cv_nm_interface="BSD nm"
-  echo "int some_variable = 0;" > conftest.$ac_ext
-  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
-  (eval "$ac_compile" 2>conftest.err)
-  cat conftest.err >&AS_MESSAGE_LOG_FD
-  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
-  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
-  cat conftest.err >&AS_MESSAGE_LOG_FD
-  (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
-  cat conftest.out >&AS_MESSAGE_LOG_FD
-  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
-    lt_cv_nm_interface="MS dumpbin"
-  fi
-  rm -f conftest*])
-])# LT_PATH_NM
-
-# Old names:
-AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
-AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AM_PROG_NM], [])
-dnl AC_DEFUN([AC_PROG_NM], [])
-
-# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
-# --------------------------------
-# how to determine the name of the shared library
-# associated with a specific link library.
-#  -- PORTME fill in with the dynamic library characteristics
-m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
-[m4_require([_LT_DECL_EGREP])
-m4_require([_LT_DECL_OBJDUMP])
-m4_require([_LT_DECL_DLLTOOL])
-AC_CACHE_CHECK([how to associate runtime and link libraries],
-lt_cv_sharedlib_from_linklib_cmd,
-[lt_cv_sharedlib_from_linklib_cmd='unknown'
-
-case $host_os in
-cygwin* | mingw* | pw32* | cegcc*)
-  # two different shell functions defined in ltmain.sh
-  # decide which to use based on capabilities of $DLLTOOL
-  case `$DLLTOOL --help 2>&1` in
-  *--identify-strict*)
-    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
-    ;;
-  *)
-    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
-    ;;
-  esac
-  ;;
-*)
-  # fallback: assume linklib IS sharedlib
-  lt_cv_sharedlib_from_linklib_cmd="$ECHO"
-  ;;
-esac
-])
-sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
-test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
-
-_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
-    [Command to associate shared and link libraries])
-])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
-
-
-# _LT_PATH_MANIFEST_TOOL
-# ----------------------
-# locate the manifest tool
-m4_defun([_LT_PATH_MANIFEST_TOOL],
-[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
-test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
-AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
-  [lt_cv_path_mainfest_tool=no
-  echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
-  $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
-  cat conftest.err >&AS_MESSAGE_LOG_FD
-  if $GREP 'Manifest Tool' conftest.out > /dev/null; then
-    lt_cv_path_mainfest_tool=yes
-  fi
-  rm -f conftest*])
-if test "x$lt_cv_path_mainfest_tool" != xyes; then
-  MANIFEST_TOOL=:
-fi
-_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
-])# _LT_PATH_MANIFEST_TOOL
-
-
-# LT_LIB_M
-# --------
-# check for math library
-AC_DEFUN([LT_LIB_M],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-LIBM=
-case $host in
-*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
-  # These system don't have libm, or don't need it
-  ;;
-*-ncr-sysv4.3*)
-  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
-  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
-  ;;
-*)
-  AC_CHECK_LIB(m, cos, LIBM="-lm")
-  ;;
-esac
-AC_SUBST([LIBM])
-])# LT_LIB_M
-
-# Old name:
-AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_CHECK_LIBM], [])
-
-
-# _LT_COMPILER_NO_RTTI([TAGNAME])
-# -------------------------------
-m4_defun([_LT_COMPILER_NO_RTTI],
-[m4_require([_LT_TAG_COMPILER])dnl
-
-_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
-
-if test "$GCC" = yes; then
-  case $cc_basename in
-  nvcc*)
-    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
-  *)
-    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
-  esac
-
-  _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
-    lt_cv_prog_compiler_rtti_exceptions,
-    [-fno-rtti -fno-exceptions], [],
-    [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
-fi
-_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
-       [Compiler flag to turn off builtin functions])
-])# _LT_COMPILER_NO_RTTI
-
-
-# _LT_CMD_GLOBAL_SYMBOLS
-# ----------------------
-m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([AC_PROG_AWK])dnl
-AC_REQUIRE([LT_PATH_NM])dnl
-AC_REQUIRE([LT_PATH_LD])dnl
-m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_TAG_COMPILER])dnl
-
-# Check for command to grab the raw symbol name followed by C symbol from nm.
-AC_MSG_CHECKING([command to parse $NM output from $compiler object])
-AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
-[
-# These are sane defaults that work on at least a few old systems.
-# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
-
-# Character class describing NM global symbol codes.
-symcode='[[BCDEGRST]]'
-
-# Regexp to match symbols that can be accessed directly from C.
-sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
-
-# Define system-specific variables.
-case $host_os in
-aix*)
-  symcode='[[BCDT]]'
-  ;;
-cygwin* | mingw* | pw32* | cegcc*)
-  symcode='[[ABCDGISTW]]'
-  ;;
-hpux*)
-  if test "$host_cpu" = ia64; then
-    symcode='[[ABCDEGRST]]'
-  fi
-  ;;
-irix* | nonstopux*)
-  symcode='[[BCDEGRST]]'
-  ;;
-osf*)
-  symcode='[[BCDEGQRST]]'
-  ;;
-solaris*)
-  symcode='[[BDRT]]'
-  ;;
-sco3.2v5*)
-  symcode='[[DT]]'
-  ;;
-sysv4.2uw2*)
-  symcode='[[DT]]'
-  ;;
-sysv5* | sco5v6* | unixware* | OpenUNIX*)
-  symcode='[[ABDT]]'
-  ;;
-sysv4)
-  symcode='[[DFNSTU]]'
-  ;;
-esac
-
-# If we're using GNU nm, then use its standard symbol codes.
-case `$NM -V 2>&1` in
-*GNU* | *'with BFD'*)
-  symcode='[[ABCDGIRSTW]]' ;;
-esac
-
-# Transform an extracted symbol line into a proper C declaration.
-# Some systems (esp. on ia64) link data and code symbols differently,
-# so use this general approach.
-lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
-
-# Transform an extracted symbol line into symbol name and symbol address
-lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p'"
-lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
-
-# Handle CRLF in mingw tool chain
-opt_cr=
-case $build_os in
-mingw*)
-  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
-  ;;
-esac
-
-# Try without a prefix underscore, then with it.
-for ac_symprfx in "" "_"; do
-
-  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
-  symxfrm="\\1 $ac_symprfx\\2 \\2"
-
-  # Write the raw and C identifiers.
-  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
-    # Fake it for dumpbin and say T for any non-static function
-    # and D for any global variable.
-    # Also find C++ and __fastcall symbols from MSVC++,
-    # which start with @ or ?.
-    lt_cv_sys_global_symbol_pipe="$AWK ['"\
-"     {last_section=section; section=\$ 3};"\
-"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
-"     \$ 0!~/External *\|/{next};"\
-"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
-"     {if(hide[section]) next};"\
-"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
-"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
-"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
-"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
-"     ' prfx=^$ac_symprfx]"
-  else
-    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[    ]]\($symcode$symcode*\)[[       ]][[    ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
-  fi
-  lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
-
-  # Check to see that the pipe works correctly.
-  pipe_works=no
-
-  rm -f conftest*
-  cat > conftest.$ac_ext <<_LT_EOF
-#ifdef __cplusplus
-extern "C" {
-#endif
-char nm_test_var;
-void nm_test_func(void);
-void nm_test_func(void){}
-#ifdef __cplusplus
-}
-#endif
-int main(){nm_test_var='a';nm_test_func();return(0);}
-_LT_EOF
-
-  if AC_TRY_EVAL(ac_compile); then
-    # Now try to grab the symbols.
-    nlist=conftest.nm
-    if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
-      # Try sorting and uniquifying the output.
-      if sort "$nlist" | uniq > "$nlist"T; then
-       mv -f "$nlist"T "$nlist"
-      else
-       rm -f "$nlist"T
-      fi
-
-      # Make sure that we snagged all the symbols we need.
-      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
-       if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
-         cat <<_LT_EOF > conftest.$ac_ext
-/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
-#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
-/* DATA imports from DLLs on WIN32 con't be const, because runtime
-   relocations are performed -- see ld's documentation on pseudo-relocs.  */
-# define LT@&t@_DLSYM_CONST
-#elif defined(__osf__)
-/* This system does not cope well with relocations in const data.  */
-# define LT@&t@_DLSYM_CONST
-#else
-# define LT@&t@_DLSYM_CONST const
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-_LT_EOF
-         # Now generate the symbol file.
-         eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
-
-         cat <<_LT_EOF >> conftest.$ac_ext
-
-/* The mapping between symbol names and symbols.  */
-LT@&t@_DLSYM_CONST struct {
-  const char *name;
-  void       *address;
-}
-lt__PROGRAM__LTX_preloaded_symbols[[]] =
-{
-  { "@PROGRAM@", (void *) 0 },
-_LT_EOF
-         $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
-         cat <<\_LT_EOF >> conftest.$ac_ext
-  {0, (void *) 0}
-};
-
-/* This works around a problem in FreeBSD linker */
-#ifdef FREEBSD_WORKAROUND
-static const void *lt_preloaded_setup() {
-  return lt__PROGRAM__LTX_preloaded_symbols;
-}
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-_LT_EOF
-         # Now try linking the two files.
-         mv conftest.$ac_objext conftstm.$ac_objext
-         lt_globsym_save_LIBS=$LIBS
-         lt_globsym_save_CFLAGS=$CFLAGS
-         LIBS="conftstm.$ac_objext"
-         CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
-         if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
-           pipe_works=yes
-         fi
-         LIBS=$lt_globsym_save_LIBS
-         CFLAGS=$lt_globsym_save_CFLAGS
-       else
-         echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
-       fi
-      else
-       echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
-      fi
-    else
-      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
-    fi
-  else
-    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
-    cat conftest.$ac_ext >&5
-  fi
-  rm -rf conftest* conftst*
-
-  # Do not use the global_symbol_pipe unless it works.
-  if test "$pipe_works" = yes; then
-    break
-  else
-    lt_cv_sys_global_symbol_pipe=
-  fi
-done
-])
-if test -z "$lt_cv_sys_global_symbol_pipe"; then
-  lt_cv_sys_global_symbol_to_cdecl=
-fi
-if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
-  AC_MSG_RESULT(failed)
-else
-  AC_MSG_RESULT(ok)
-fi
-
-# Response file support.
-if test "$lt_cv_nm_interface" = "MS dumpbin"; then
-  nm_file_list_spec='@'
-elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
-  nm_file_list_spec='@'
-fi
-
-_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
-    [Take the output of nm and produce a listing of raw symbols and C names])
-_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
-    [Transform the output of nm in a proper C declaration])
-_LT_DECL([global_symbol_to_c_name_address],
-    [lt_cv_sys_global_symbol_to_c_name_address], [1],
-    [Transform the output of nm in a C name address pair])
-_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
-    [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
-    [Transform the output of nm in a C name address pair when lib prefix is needed])
-_LT_DECL([], [nm_file_list_spec], [1],
-    [Specify filename containing input files for $NM])
-]) # _LT_CMD_GLOBAL_SYMBOLS
-
-
-# _LT_COMPILER_PIC([TAGNAME])
-# ---------------------------
-m4_defun([_LT_COMPILER_PIC],
-[m4_require([_LT_TAG_COMPILER])dnl
-_LT_TAGVAR(lt_prog_compiler_wl, $1)=
-_LT_TAGVAR(lt_prog_compiler_pic, $1)=
-_LT_TAGVAR(lt_prog_compiler_static, $1)=
-
-m4_if([$1], [CXX], [
-  # C++ specific cases for pic, static, wl, etc.
-  if test "$GXX" = yes; then
-    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-
-    case $host_os in
-    aix*)
-      # All AIX code is PIC.
-      if test "$host_cpu" = ia64; then
-       # AIX 5 now supports IA64 processor
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      fi
-      ;;
-
-    amigaos*)
-      case $host_cpu in
-      powerpc)
-            # see comment about AmigaOS4 .so support
-            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-        ;;
-      m68k)
-            # FIXME: we need at least 68020 code to build shared libraries, but
-            # adding the `-m68020' flag to GCC prevents building anything better,
-            # like `-m68040'.
-            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
-        ;;
-      esac
-      ;;
-
-    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
-      # PIC is the default for these OSes.
-      ;;
-    mingw* | cygwin* | os2* | pw32* | cegcc*)
-      # This hack is so that the source file can tell whether it is being
-      # built for inclusion in a dll (and should export symbols for example).
-      # Although the cygwin gcc ignores -fPIC, still need this for old-style
-      # (--disable-auto-import) libraries
-      m4_if([$1], [GCJ], [],
-       [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
-      ;;
-    darwin* | rhapsody*)
-      # PIC is the default on this platform
-      # Common symbols not allowed in MH_DYLIB files
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
-      ;;
-    *djgpp*)
-      # DJGPP does not support shared libraries at all
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)=
-      ;;
-    haiku*)
-      # PIC is the default for Haiku.
-      # The "-static" flag exists, but is broken.
-      _LT_TAGVAR(lt_prog_compiler_static, $1)=
-      ;;
-    interix[[3-9]]*)
-      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
-      # Instead, we relocate shared libraries at runtime.
-      ;;
-    sysv4*MP*)
-      if test -d /usr/nec; then
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
-      fi
-      ;;
-    hpux*)
-      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
-      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
-      # sets the default TLS model and affects inlining.
-      case $host_cpu in
-      hppa*64*)
-       ;;
-      *)
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-       ;;
-      esac
-      ;;
-    *qnx* | *nto*)
-      # QNX uses GNU C++, but need to define -shared option too, otherwise
-      # it will coredump.
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
-      ;;
-    *)
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-      ;;
-    esac
-  else
-    case $host_os in
-      aix[[4-9]]*)
-       # All AIX code is PIC.
-       if test "$host_cpu" = ia64; then
-         # AIX 5 now supports IA64 processor
-         _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-       else
-         _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
-       fi
-       ;;
-      chorus*)
-       case $cc_basename in
-       cxch68*)
-         # Green Hills C++ Compiler
-         # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
-         ;;
-       esac
-       ;;
-      mingw* | cygwin* | os2* | pw32* | cegcc*)
-       # This hack is so that the source file can tell whether it is being
-       # built for inclusion in a dll (and should export symbols for example).
-       m4_if([$1], [GCJ], [],
-         [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
-       ;;
-      dgux*)
-       case $cc_basename in
-         ec++*)
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-           ;;
-         ghcx*)
-           # Green Hills C++ Compiler
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
-           ;;
-         *)
-           ;;
-       esac
-       ;;
-      freebsd* | dragonfly*)
-       # FreeBSD uses GNU C++
-       ;;
-      hpux9* | hpux10* | hpux11*)
-       case $cc_basename in
-         CC*)
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
-           if test "$host_cpu" != ia64; then
-             _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
-           fi
-           ;;
-         aCC*)
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
-           case $host_cpu in
-           hppa*64*|ia64*)
-             # +Z the default
-             ;;
-           *)
-             _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
-             ;;
-           esac
-           ;;
-         *)
-           ;;
-       esac
-       ;;
-      interix*)
-       # This is c89, which is MS Visual C++ (no shared libs)
-       # Anyone wants to do a port?
-       ;;
-      irix5* | irix6* | nonstopux*)
-       case $cc_basename in
-         CC*)
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-           # CC pic flag -KPIC is the default.
-           ;;
-         *)
-           ;;
-       esac
-       ;;
-      linux* | k*bsd*-gnu | kopensolaris*-gnu)
-       case $cc_basename in
-         KCC*)
-           # KAI C++ Compiler
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-           ;;
-         ecpc* )
-           # old Intel C++ for x86_64 which still supported -KPIC.
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-           ;;
-         icpc* )
-           # Intel C++, used to be incompatible with GCC.
-           # ICC 10 doesn't accept -KPIC any more.
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-           ;;
-         pgCC* | pgcpp*)
-           # Portland Group C++ compiler
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-           ;;
-         cxx*)
-           # Compaq C++
-           # Make sure the PIC flag is empty.  It appears that all Alpha
-           # Linux and Compaq Tru64 Unix objects are PIC.
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)=
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-           ;;
-         xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
-           # IBM XL 8.0, 9.0 on PPC and BlueGene
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
-           ;;
-         *)
-           case `$CC -V 2>&1 | sed 5q` in
-           *Sun\ C*)
-             # Sun C++ 5.9
-             _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-             _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-             _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
-             ;;
-           esac
-           ;;
-       esac
-       ;;
-      lynxos*)
-       ;;
-      m88k*)
-       ;;
-      mvs*)
-       case $cc_basename in
-         cxx*)
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
-           ;;
-         *)
-           ;;
-       esac
-       ;;
-      netbsd*)
-       ;;
-      *qnx* | *nto*)
-        # QNX uses GNU C++, but need to define -shared option too, otherwise
-        # it will coredump.
-        _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
-        ;;
-      osf3* | osf4* | osf5*)
-       case $cc_basename in
-         KCC*)
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
-           ;;
-         RCC*)
-           # Rational C++ 2.4.1
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
-           ;;
-         cxx*)
-           # Digital/Compaq C++
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-           # Make sure the PIC flag is empty.  It appears that all Alpha
-           # Linux and Compaq Tru64 Unix objects are PIC.
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)=
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-           ;;
-         *)
-           ;;
-       esac
-       ;;
-      psos*)
-       ;;
-      solaris*)
-       case $cc_basename in
-         CC* | sunCC*)
-           # Sun C++ 4.2, 5.x and Centerline C++
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
-           ;;
-         gcx*)
-           # Green Hills C++ Compiler
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
-           ;;
-         *)
-           ;;
-       esac
-       ;;
-      sunos4*)
-       case $cc_basename in
-         CC*)
-           # Sun C++ 4.x
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-           ;;
-         lcc*)
-           # Lucid
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
-           ;;
-         *)
-           ;;
-       esac
-       ;;
-      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
-       case $cc_basename in
-         CC*)
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-           ;;
-       esac
-       ;;
-      tandem*)
-       case $cc_basename in
-         NCC*)
-           # NonStop-UX NCC 3.20
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-           ;;
-         *)
-           ;;
-       esac
-       ;;
-      vxworks*)
-       ;;
-      *)
-       _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
-       ;;
-    esac
-  fi
-],
-[
-  if test "$GCC" = yes; then
-    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-
-    case $host_os in
-      aix*)
-      # All AIX code is PIC.
-      if test "$host_cpu" = ia64; then
-       # AIX 5 now supports IA64 processor
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      fi
-      ;;
-
-    amigaos*)
-      case $host_cpu in
-      powerpc)
-            # see comment about AmigaOS4 .so support
-            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-        ;;
-      m68k)
-            # FIXME: we need at least 68020 code to build shared libraries, but
-            # adding the `-m68020' flag to GCC prevents building anything better,
-            # like `-m68040'.
-            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
-        ;;
-      esac
-      ;;
-
-    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
-      # PIC is the default for these OSes.
-      ;;
-
-    mingw* | cygwin* | pw32* | os2* | cegcc*)
-      # This hack is so that the source file can tell whether it is being
-      # built for inclusion in a dll (and should export symbols for example).
-      # Although the cygwin gcc ignores -fPIC, still need this for old-style
-      # (--disable-auto-import) libraries
-      m4_if([$1], [GCJ], [],
-       [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
-      ;;
-
-    darwin* | rhapsody*)
-      # PIC is the default on this platform
-      # Common symbols not allowed in MH_DYLIB files
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
-      ;;
-
-    haiku*)
-      # PIC is the default for Haiku.
-      # The "-static" flag exists, but is broken.
-      _LT_TAGVAR(lt_prog_compiler_static, $1)=
-      ;;
-
-    hpux*)
-      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
-      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
-      # sets the default TLS model and affects inlining.
-      case $host_cpu in
-      hppa*64*)
-       # +Z the default
-       ;;
-      *)
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-       ;;
-      esac
-      ;;
-
-    interix[[3-9]]*)
-      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
-      # Instead, we relocate shared libraries at runtime.
-      ;;
-
-    msdosdjgpp*)
-      # Just because we use GCC doesn't mean we suddenly get shared libraries
-      # on systems that don't support them.
-      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
-      enable_shared=no
-      ;;
-
-    *nto* | *qnx*)
-      # QNX uses GNU C++, but need to define -shared option too, otherwise
-      # it will coredump.
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
-      ;;
-
-    sysv4*MP*)
-      if test -d /usr/nec; then
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
-      fi
-      ;;
-
-    *)
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-      ;;
-    esac
-
-    case $cc_basename in
-    nvcc*) # Cuda Compiler Driver 2.2
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Xcompiler -fPIC'
-      ;;
-    esac
-  else
-    # PORTME Check for flag to pass linker flags through the system compiler.
-    case $host_os in
-    aix*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      if test "$host_cpu" = ia64; then
-       # AIX 5 now supports IA64 processor
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      else
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
-      fi
-      ;;
-
-    mingw* | cygwin* | pw32* | os2* | cegcc*)
-      # This hack is so that the source file can tell whether it is being
-      # built for inclusion in a dll (and should export symbols for example).
-      m4_if([$1], [GCJ], [],
-       [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
-      ;;
-
-    hpux9* | hpux10* | hpux11*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
-      # not for PA HP-UX.
-      case $host_cpu in
-      hppa*64*|ia64*)
-       # +Z the default
-       ;;
-      *)
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
-       ;;
-      esac
-      # Is there a better lt_prog_compiler_static that works with the bundled CC?
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
-      ;;
-
-    irix5* | irix6* | nonstopux*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      # PIC (with -KPIC) is the default.
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-      ;;
-
-    linux* | k*bsd*-gnu | kopensolaris*-gnu)
-      case $cc_basename in
-      # old Intel for x86_64 which still supported -KPIC.
-      ecc*)
-       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-        ;;
-      # icc used to be incompatible with GCC.
-      # ICC 10 doesn't accept -KPIC any more.
-      icc* | ifort*)
-       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-        ;;
-      # Lahey Fortran 8.1.
-      lf95*)
-       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
-       ;;
-      nagfor*)
-       # NAG Fortran compiler
-       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-       ;;
-      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
-        # Portland Group compilers (*not* the Pentium gcc compiler,
-       # which looks to be a dead project)
-       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-        ;;
-      ccc*)
-        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-        # All Alpha code is PIC.
-        _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-        ;;
-      xl* | bgxl* | bgf* | mpixl*)
-       # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
-       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
-       ;;
-      *)
-       case `$CC -V 2>&1 | sed 5q` in
-       *Sun\ F* | *Sun*Fortran*)
-         # Sun Fortran 8.3 passes all unrecognized flags to the linker
-         _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-         _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-         _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
-         ;;
-       *Sun\ C*)
-         # Sun C 5.9
-         _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-         _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-         _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-         ;;
-       esac
-       ;;
-      esac
-      ;;
-
-    newsos6)
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      ;;
-
-    *nto* | *qnx*)
-      # QNX uses GNU C++, but need to define -shared option too, otherwise
-      # it will coredump.
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
-      ;;
-
-    osf3* | osf4* | osf5*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      # All OSF/1 code is PIC.
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-      ;;
-
-    rdos*)
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-      ;;
-
-    solaris*)
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      case $cc_basename in
-      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
-       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
-      *)
-       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
-      esac
-      ;;
-
-    sunos4*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      ;;
-
-    sysv4 | sysv4.2uw2* | sysv4.3*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      ;;
-
-    sysv4*MP*)
-      if test -d /usr/nec ;then
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      fi
-      ;;
-
-    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      ;;
-
-    unicos*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
-      ;;
-
-    uts4*)
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      ;;
-
-    *)
-      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
-      ;;
-    esac
-  fi
-])
-case $host_os in
-  # For platforms which do not support PIC, -DPIC is meaningless:
-  *djgpp*)
-    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
-    ;;
-  *)
-    _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
-    ;;
-esac
-
-AC_CACHE_CHECK([for $compiler option to produce PIC],
-  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
-  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
-_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
-
-#
-# Check to make sure the PIC flag actually works.
-#
-if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
-  _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
-    [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
-    [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
-    [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
-     "" | " "*) ;;
-     *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
-     esac],
-    [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
-     _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
-fi
-_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
-       [Additional compiler flags for building library objects])
-
-_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
-       [How to pass a linker flag through the compiler])
-#
-# Check to make sure the static flag actually works.
-#
-wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
-_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
-  _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
-  $lt_tmp_static_flag,
-  [],
-  [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
-_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
-       [Compiler flag to prevent dynamic linking])
-])# _LT_COMPILER_PIC
-
-
-# _LT_LINKER_SHLIBS([TAGNAME])
-# ----------------------------
-# See if the linker supports building shared libraries.
-m4_defun([_LT_LINKER_SHLIBS],
-[AC_REQUIRE([LT_PATH_LD])dnl
-AC_REQUIRE([LT_PATH_NM])dnl
-m4_require([_LT_PATH_MANIFEST_TOOL])dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
-m4_require([_LT_TAG_COMPILER])dnl
-AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
-m4_if([$1], [CXX], [
-  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
-  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
-  case $host_os in
-  aix[[4-9]]*)
-    # If we're using GNU nm, then we don't want the "-C" option.
-    # -C means demangle to AIX nm, but means don't demangle with GNU nm
-    # Also, AIX nm treats weak defined symbols like other global defined
-    # symbols, whereas GNU nm marks them as "W".
-    if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
-      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
-    else
-      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
-    fi
-    ;;
-  pw32*)
-    _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
-    ;;
-  cygwin* | mingw* | cegcc*)
-    case $cc_basename in
-    cl*) ;;
-    *)
-      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
-      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
-      ;;
-    esac
-    ;;
-  *)
-    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
-    ;;
-  esac
-], [
-  runpath_var=
-  _LT_TAGVAR(allow_undefined_flag, $1)=
-  _LT_TAGVAR(always_export_symbols, $1)=no
-  _LT_TAGVAR(archive_cmds, $1)=
-  _LT_TAGVAR(archive_expsym_cmds, $1)=
-  _LT_TAGVAR(compiler_needs_object, $1)=no
-  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
-  _LT_TAGVAR(export_dynamic_flag_spec, $1)=
-  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
-  _LT_TAGVAR(hardcode_automatic, $1)=no
-  _LT_TAGVAR(hardcode_direct, $1)=no
-  _LT_TAGVAR(hardcode_direct_absolute, $1)=no
-  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-  _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
-  _LT_TAGVAR(hardcode_libdir_separator, $1)=
-  _LT_TAGVAR(hardcode_minus_L, $1)=no
-  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
-  _LT_TAGVAR(inherit_rpath, $1)=no
-  _LT_TAGVAR(link_all_deplibs, $1)=unknown
-  _LT_TAGVAR(module_cmds, $1)=
-  _LT_TAGVAR(module_expsym_cmds, $1)=
-  _LT_TAGVAR(old_archive_from_new_cmds, $1)=
-  _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
-  _LT_TAGVAR(thread_safe_flag_spec, $1)=
-  _LT_TAGVAR(whole_archive_flag_spec, $1)=
-  # include_expsyms should be a list of space-separated symbols to be *always*
-  # included in the symbol list
-  _LT_TAGVAR(include_expsyms, $1)=
-  # exclude_expsyms can be an extended regexp of symbols to exclude
-  # it will be wrapped by ` (' and `)$', so one must not match beginning or
-  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
-  # as well as any symbol that contains `d'.
-  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
-  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
-  # platforms (ab)use it in PIC code, but their linkers get confused if
-  # the symbol is explicitly referenced.  Since portable code cannot
-  # rely on this symbol name, it's probably fine to never include it in
-  # preloaded symbol tables.
-  # Exclude shared library initialization/finalization symbols.
-dnl Note also adjust exclude_expsyms for C++ above.
-  extract_expsyms_cmds=
-
-  case $host_os in
-  cygwin* | mingw* | pw32* | cegcc*)
-    # FIXME: the MSVC++ port hasn't been tested in a loooong time
-    # When not using gcc, we currently assume that we are using
-    # Microsoft Visual C++.
-    if test "$GCC" != yes; then
-      with_gnu_ld=no
-    fi
-    ;;
-  interix*)
-    # we just hope/assume this is gcc and not c89 (= MSVC++)
-    with_gnu_ld=yes
-    ;;
-  openbsd*)
-    with_gnu_ld=no
-    ;;
-  esac
-
-  _LT_TAGVAR(ld_shlibs, $1)=yes
-
-  # On some targets, GNU ld is compatible enough with the native linker
-  # that we're better off using the native interface for both.
-  lt_use_gnu_ld_interface=no
-  if test "$with_gnu_ld" = yes; then
-    case $host_os in
-      aix*)
-       # The AIX port of GNU ld has always aspired to compatibility
-       # with the native linker.  However, as the warning in the GNU ld
-       # block says, versions before 2.19.5* couldn't really create working
-       # shared libraries, regardless of the interface used.
-       case `$LD -v 2>&1` in
-         *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
-         *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
-         *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
-         *)
-           lt_use_gnu_ld_interface=yes
-           ;;
-       esac
-       ;;
-      *)
-       lt_use_gnu_ld_interface=yes
-       ;;
-    esac
-  fi
-
-  if test "$lt_use_gnu_ld_interface" = yes; then
-    # If archive_cmds runs LD, not CC, wlarc should be empty
-    wlarc='${wl}'
-
-    # Set some defaults for GNU ld with shared library support. These
-    # are reset later if shared libraries are not supported. Putting them
-    # here allows them to be overridden if necessary.
-    runpath_var=LD_RUN_PATH
-    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
-    # ancient GNU ld didn't support --whole-archive et. al.
-    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
-      _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
-    else
-      _LT_TAGVAR(whole_archive_flag_spec, $1)=
-    fi
-    supports_anon_versioning=no
-    case `$LD -v 2>&1` in
-      *GNU\ gold*) supports_anon_versioning=yes ;;
-      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
-      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
-      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
-      *\ 2.11.*) ;; # other 2.11 versions
-      *) supports_anon_versioning=yes ;;
-    esac
-
-    # See if GNU ld supports shared libraries.
-    case $host_os in
-    aix[[3-9]]*)
-      # On AIX/PPC, the GNU linker is very broken
-      if test "$host_cpu" != ia64; then
-       _LT_TAGVAR(ld_shlibs, $1)=no
-       cat <<_LT_EOF 1>&2
-
-*** Warning: the GNU linker, at least up to release 2.19, is reported
-*** to be unable to reliably create shared libraries on AIX.
-*** Therefore, libtool is disabling shared libraries support.  If you
-*** really care for shared libraries, you may want to install binutils
-*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
-*** You will then need to restart the configuration process.
-
-_LT_EOF
-      fi
-      ;;
-
-    amigaos*)
-      case $host_cpu in
-      powerpc)
-            # see comment about AmigaOS4 .so support
-            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-            _LT_TAGVAR(archive_expsym_cmds, $1)=''
-        ;;
-      m68k)
-            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
-            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-            _LT_TAGVAR(hardcode_minus_L, $1)=yes
-        ;;
-      esac
-      ;;
-
-    beos*)
-      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-       _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-       # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
-       # support --undefined.  This deserves some investigation.  FIXME
-       _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-      else
-       _LT_TAGVAR(ld_shlibs, $1)=no
-      fi
-      ;;
-
-    cygwin* | mingw* | pw32* | cegcc*)
-      # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
-      # as there is no search path for DLLs.
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
-      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-      _LT_TAGVAR(always_export_symbols, $1)=no
-      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
-      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
-
-      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
-        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
-       # If the export-symbols file already is a .def file (1st line
-       # is EXPORTS), use it as is; otherwise, prepend...
-       _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
-         cp $export_symbols $output_objdir/$soname.def;
-       else
-         echo EXPORTS > $output_objdir/$soname.def;
-         cat $export_symbols >> $output_objdir/$soname.def;
-       fi~
-       $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
-      else
-       _LT_TAGVAR(ld_shlibs, $1)=no
-      fi
-      ;;
-
-    haiku*)
-      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-      _LT_TAGVAR(link_all_deplibs, $1)=yes
-      ;;
-
-    interix[[3-9]]*)
-      _LT_TAGVAR(hardcode_direct, $1)=no
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
-      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
-      # Instead, shared libraries are loaded at an image base (0x10000000 by
-      # default) and relocated if they conflict, which is a slow very memory
-      # consuming and fragmenting process.  To avoid this, we pick a random,
-      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
-      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
-      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
-      _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
-      ;;
-
-    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
-      tmp_diet=no
-      if test "$host_os" = linux-dietlibc; then
-       case $cc_basename in
-         diet\ *) tmp_diet=yes;;       # linux-dietlibc with static linking (!diet-dyn)
-       esac
-      fi
-      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
-        && test "$tmp_diet" = no
-      then
-       tmp_addflag=' $pic_flag'
-       tmp_sharedflag='-shared'
-       case $cc_basename,$host_cpu in
-        pgcc*)                         # Portland Group C compiler
-         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
-         tmp_addflag=' $pic_flag'
-         ;;
-       pgf77* | pgf90* | pgf95* | pgfortran*)
-                                       # Portland Group f77 and f90 compilers
-         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
-         tmp_addflag=' $pic_flag -Mnomain' ;;
-       ecc*,ia64* | icc*,ia64*)        # Intel C compiler on ia64
-         tmp_addflag=' -i_dynamic' ;;
-       efc*,ia64* | ifort*,ia64*)      # Intel Fortran compiler on ia64
-         tmp_addflag=' -i_dynamic -nofor_main' ;;
-       ifc* | ifort*)                  # Intel Fortran compiler
-         tmp_addflag=' -nofor_main' ;;
-       lf95*)                          # Lahey Fortran 8.1
-         _LT_TAGVAR(whole_archive_flag_spec, $1)=
-         tmp_sharedflag='--shared' ;;
-       xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
-         tmp_sharedflag='-qmkshrobj'
-         tmp_addflag= ;;
-       nvcc*)  # Cuda Compiler Driver 2.2
-         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
-         _LT_TAGVAR(compiler_needs_object, $1)=yes
-         ;;
-       esac
-       case `$CC -V 2>&1 | sed 5q` in
-       *Sun\ C*)                       # Sun C 5.9
-         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
-         _LT_TAGVAR(compiler_needs_object, $1)=yes
-         tmp_sharedflag='-G' ;;
-       *Sun\ F*)                       # Sun Fortran 8.3
-         tmp_sharedflag='-G' ;;
-       esac
-       _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-
-        if test "x$supports_anon_versioning" = xyes; then
-          _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
-           cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-           echo "local: *; };" >> $output_objdir/$libname.ver~
-           $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
-        fi
-
-       case $cc_basename in
-       xlf* | bgf* | bgxlf* | mpixlf*)
-         # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
-         _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
-         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-         _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir'
-         _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
-         if test "x$supports_anon_versioning" = xyes; then
-           _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
-             cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-             echo "local: *; };" >> $output_objdir/$libname.ver~
-             $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
-         fi
-         ;;
-       esac
-      else
-        _LT_TAGVAR(ld_shlibs, $1)=no
-      fi
-      ;;
-
-    netbsd*)
-      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
-       _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
-       wlarc=
-      else
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
-      fi
-      ;;
-
-    solaris*)
-      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
-       _LT_TAGVAR(ld_shlibs, $1)=no
-       cat <<_LT_EOF 1>&2
-
-*** Warning: The releases 2.8.* of the GNU linker cannot reliably
-*** create shared libraries on Solaris systems.  Therefore, libtool
-*** is disabling shared libraries support.  We urge you to upgrade GNU
-*** binutils to release 2.9.1 or newer.  Another option is to modify
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-_LT_EOF
-      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
-      else
-       _LT_TAGVAR(ld_shlibs, $1)=no
-      fi
-      ;;
-
-    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
-      case `$LD -v 2>&1` in
-        *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
-       _LT_TAGVAR(ld_shlibs, $1)=no
-       cat <<_LT_EOF 1>&2
-
-*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
-*** reliably create shared libraries on SCO systems.  Therefore, libtool
-*** is disabling shared libraries support.  We urge you to upgrade GNU
-*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-_LT_EOF
-       ;;
-       *)
-         # For security reasons, it is highly recommended that you always
-         # use absolute paths for naming shared libraries, and exclude the
-         # DT_RUNPATH tag from executables and libraries.  But doing so
-         # requires that you compile everything twice, which is a pain.
-         if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-           _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
-         else
-           _LT_TAGVAR(ld_shlibs, $1)=no
-         fi
-       ;;
-      esac
-      ;;
-
-    sunos4*)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
-      wlarc=
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    *)
-      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
-      else
-       _LT_TAGVAR(ld_shlibs, $1)=no
-      fi
-      ;;
-    esac
-
-    if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
-      runpath_var=
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)=
-      _LT_TAGVAR(whole_archive_flag_spec, $1)=
-    fi
-  else
-    # PORTME fill in a description of your system's linker (not GNU ld)
-    case $host_os in
-    aix3*)
-      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-      _LT_TAGVAR(always_export_symbols, $1)=yes
-      _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
-      # Note: this linker hardcodes the directories in LIBPATH if there
-      # are no directories specified by -L.
-      _LT_TAGVAR(hardcode_minus_L, $1)=yes
-      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
-       # Neither direct hardcoding nor static linking is supported with a
-       # broken collect2.
-       _LT_TAGVAR(hardcode_direct, $1)=unsupported
-      fi
-      ;;
-
-    aix[[4-9]]*)
-      if test "$host_cpu" = ia64; then
-       # On IA64, the linker does run time linking by default, so we don't
-       # have to do anything special.
-       aix_use_runtimelinking=no
-       exp_sym_flag='-Bexport'
-       no_entry_flag=""
-      else
-       # If we're using GNU nm, then we don't want the "-C" option.
-       # -C means demangle to AIX nm, but means don't demangle with GNU nm
-       # Also, AIX nm treats weak defined symbols like other global
-       # defined symbols, whereas GNU nm marks them as "W".
-       if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
-         _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
-       else
-         _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
-       fi
-       aix_use_runtimelinking=no
-
-       # Test if we are trying to use run time linking or normal
-       # AIX style linking. If -brtl is somewhere in LDFLAGS, we
-       # need to do runtime linking.
-       case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
-         for ld_flag in $LDFLAGS; do
-         if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
-           aix_use_runtimelinking=yes
-           break
-         fi
-         done
-         ;;
-       esac
-
-       exp_sym_flag='-bexport'
-       no_entry_flag='-bnoentry'
-      fi
-
-      # When large executables or shared objects are built, AIX ld can
-      # have problems creating the table of contents.  If linking a library
-      # or program results in "error TOC overflow" add -mminimal-toc to
-      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
-      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
-
-      _LT_TAGVAR(archive_cmds, $1)=''
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
-      _LT_TAGVAR(link_all_deplibs, $1)=yes
-      _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
-
-      if test "$GCC" = yes; then
-       case $host_os in aix4.[[012]]|aix4.[[012]].*)
-       # We only want to do this on AIX 4.2 and lower, the check
-       # below for broken collect2 doesn't work under 4.3+
-         collect2name=`${CC} -print-prog-name=collect2`
-         if test -f "$collect2name" &&
-          strings "$collect2name" | $GREP resolve_lib_name >/dev/null
-         then
-         # We have reworked collect2
-         :
-         else
-         # We have old collect2
-         _LT_TAGVAR(hardcode_direct, $1)=unsupported
-         # It fails to find uninstalled libraries when the uninstalled
-         # path is not listed in the libpath.  Setting hardcode_minus_L
-         # to unsupported forces relinking
-         _LT_TAGVAR(hardcode_minus_L, $1)=yes
-         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-         _LT_TAGVAR(hardcode_libdir_separator, $1)=
-         fi
-         ;;
-       esac
-       shared_flag='-shared'
-       if test "$aix_use_runtimelinking" = yes; then
-         shared_flag="$shared_flag "'${wl}-G'
-       fi
-      else
-       # not using gcc
-       if test "$host_cpu" = ia64; then
-       # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
-       # chokes on -Wl,-G. The following line is correct:
-         shared_flag='-G'
-       else
-         if test "$aix_use_runtimelinking" = yes; then
-           shared_flag='${wl}-G'
-         else
-           shared_flag='${wl}-bM:SRE'
-         fi
-       fi
-      fi
-
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
-      # It seems that -bexpall does not export symbols beginning with
-      # underscore (_), so it is better to generate a list of symbols to export.
-      _LT_TAGVAR(always_export_symbols, $1)=yes
-      if test "$aix_use_runtimelinking" = yes; then
-       # Warning - without using the other runtime loading flags (-brtl),
-       # -berok will link without error, but may produce a broken library.
-       _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
-        # Determine the default libpath from the value encoded in an
-        # empty executable.
-        _LT_SYS_MODULE_PATH_AIX([$1])
-        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
-        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
-      else
-       if test "$host_cpu" = ia64; then
-         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
-         _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
-         _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
-       else
-        # Determine the default libpath from the value encoded in an
-        # empty executable.
-        _LT_SYS_MODULE_PATH_AIX([$1])
-        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
-         # Warning - without using the other run time loading flags,
-         # -berok will link without error, but may produce a broken library.
-         _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
-         _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
-         if test "$with_gnu_ld" = yes; then
-           # We only use this code for GNU lds that support --whole-archive.
-           _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
-         else
-           # Exported symbols can be pulled into shared objects from archives
-           _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
-         fi
-         _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
-         # This is similar to how AIX traditionally builds its shared libraries.
-         _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
-       fi
-      fi
-      ;;
-
-    amigaos*)
-      case $host_cpu in
-      powerpc)
-            # see comment about AmigaOS4 .so support
-            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-            _LT_TAGVAR(archive_expsym_cmds, $1)=''
-        ;;
-      m68k)
-            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
-            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-            _LT_TAGVAR(hardcode_minus_L, $1)=yes
-        ;;
-      esac
-      ;;
-
-    bsdi[[45]]*)
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
-      ;;
-
-    cygwin* | mingw* | pw32* | cegcc*)
-      # When not using gcc, we currently assume that we are using
-      # Microsoft Visual C++.
-      # hardcode_libdir_flag_spec is actually meaningless, as there is
-      # no search path for DLLs.
-      case $cc_basename in
-      cl*)
-       # Native MSVC
-       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
-       _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-       _LT_TAGVAR(always_export_symbols, $1)=yes
-       _LT_TAGVAR(file_list_spec, $1)='@'
-       # Tell ltmain to make .lib files, not .a files.
-       libext=lib
-       # Tell ltmain to make .dll files, not .so files.
-       shrext_cmds=".dll"
-       # FIXME: Setting linknames here is a bad hack.
-       _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
-       _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
-           sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
-         else
-           sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
-         fi~
-         $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
-         linknames='
-       # The linker will not automatically build a static lib if we build a DLL.
-       # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
-       _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-       _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
-       # Don't use ranlib
-       _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
-       _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
-         lt_tool_outputfile="@TOOL_OUTPUT@"~
-         case $lt_outputfile in
-           *.exe|*.EXE) ;;
-           *)
-             lt_outputfile="$lt_outputfile.exe"
-             lt_tool_outputfile="$lt_tool_outputfile.exe"
-             ;;
-         esac~
-         if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
-           $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
-           $RM "$lt_outputfile.manifest";
-         fi'
-       ;;
-      *)
-       # Assume MSVC wrapper
-       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
-       _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-       # Tell ltmain to make .lib files, not .a files.
-       libext=lib
-       # Tell ltmain to make .dll files, not .so files.
-       shrext_cmds=".dll"
-       # FIXME: Setting linknames here is a bad hack.
-       _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
-       # The linker will automatically build a .lib file if we build a DLL.
-       _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
-       # FIXME: Should let the user specify the lib program.
-       _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
-       _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-       ;;
-      esac
-      ;;
-
-    darwin* | rhapsody*)
-      _LT_DARWIN_LINKER_FEATURES($1)
-      ;;
-
-    dgux*)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    freebsd1*)
-      _LT_TAGVAR(ld_shlibs, $1)=no
-      ;;
-
-    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
-    # support.  Future versions do this automatically, but an explicit c++rt0.o
-    # does not break anything, and helps significantly (at the cost of a little
-    # extra space).
-    freebsd2.2*)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
-    freebsd2*)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_minus_L, $1)=yes
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
-    freebsd* | dragonfly*)
-      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    hpux9*)
-      if test "$GCC" = yes; then
-       _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
-      else
-       _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
-      fi
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-
-      # hardcode_minus_L: Not really in the search PATH,
-      # but as the default location of the library.
-      _LT_TAGVAR(hardcode_minus_L, $1)=yes
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
-      ;;
-
-    hpux10*)
-      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
-      else
-       _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
-      fi
-      if test "$with_gnu_ld" = no; then
-       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
-       _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
-       _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-       _LT_TAGVAR(hardcode_direct, $1)=yes
-       _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-       _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
-       # hardcode_minus_L: Not really in the search PATH,
-       # but as the default location of the library.
-       _LT_TAGVAR(hardcode_minus_L, $1)=yes
-      fi
-      ;;
-
-    hpux11*)
-      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
-       case $host_cpu in
-       hppa*64*)
-         _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
-         ;;
-       ia64*)
-         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
-         ;;
-       *)
-         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
-         ;;
-       esac
-      else
-       case $host_cpu in
-       hppa*64*)
-         _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
-         ;;
-       ia64*)
-         _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
-         ;;
-       *)
-       m4_if($1, [], [
-         # Older versions of the 11.00 compiler do not understand -b yet
-         # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
-         _LT_LINKER_OPTION([if $CC understands -b],
-           _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
-           [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
-           [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
-         [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
-         ;;
-       esac
-      fi
-      if test "$with_gnu_ld" = no; then
-       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
-       _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
-       case $host_cpu in
-       hppa*64*|ia64*)
-         _LT_TAGVAR(hardcode_direct, $1)=no
-         _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-         ;;
-       *)
-         _LT_TAGVAR(hardcode_direct, $1)=yes
-         _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-         _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
-
-         # hardcode_minus_L: Not really in the search PATH,
-         # but as the default location of the library.
-         _LT_TAGVAR(hardcode_minus_L, $1)=yes
-         ;;
-       esac
-      fi
-      ;;
-
-    irix5* | irix6* | nonstopux*)
-      if test "$GCC" = yes; then
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
-       # Try to use the -exported_symbol ld option, if it does not
-       # work, assume that -exports_file does not work either and
-       # implicitly export all symbols.
-       # This should be the same for all languages, so no per-tag cache variable.
-       AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
-         [lt_cv_irix_exported_symbol],
-         [save_LDFLAGS="$LDFLAGS"
-          LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
-          AC_LINK_IFELSE(
-            [AC_LANG_SOURCE(
-               [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
-                             [C++], [[int foo (void) { return 0; }]],
-                             [Fortran 77], [[
-      subroutine foo
-      end]],
-                             [Fortran], [[
-      subroutine foo
-      end]])])],
-             [lt_cv_irix_exported_symbol=yes],
-             [lt_cv_irix_exported_symbol=no])
-           LDFLAGS="$save_LDFLAGS"])
-       if test "$lt_cv_irix_exported_symbol" = yes; then
-          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
-       fi
-      else
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
-      fi
-      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-      _LT_TAGVAR(inherit_rpath, $1)=yes
-      _LT_TAGVAR(link_all_deplibs, $1)=yes
-      ;;
-
-    netbsd*)
-      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
-       _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
-      else
-       _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
-      fi
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    newsos6)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    *nto* | *qnx*)
-      ;;
-
-    openbsd*)
-      if test -f /usr/libexec/ld.so; then
-       _LT_TAGVAR(hardcode_direct, $1)=yes
-       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-       _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-       if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
-         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
-         _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
-         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-         _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
-       else
-         case $host_os in
-          openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
-            _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
-            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-            ;;
-          *)
-            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
-            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-            ;;
-         esac
-       fi
-      else
-       _LT_TAGVAR(ld_shlibs, $1)=no
-      fi
-      ;;
-
-    os2*)
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-      _LT_TAGVAR(hardcode_minus_L, $1)=yes
-      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
-      _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
-      ;;
-
-    osf3*)
-      if test "$GCC" = yes; then
-       _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
-      else
-       _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
-      fi
-      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-      ;;
-
-    osf4* | osf5*)     # as osf3* with the addition of -msym flag
-      if test "$GCC" = yes; then
-       _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
-       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-      else
-       _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
-       $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
-
-       # Both c and cxx compiler support -rpath directly
-       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
-      fi
-      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-      ;;
-
-    solaris*)
-      _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
-      if test "$GCC" = yes; then
-       wlarc='${wl}'
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-         $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
-      else
-       case `$CC -V 2>&1` in
-       *"Compilers 5.0"*)
-         wlarc=''
-         _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
-         _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-         $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
-         ;;
-       *)
-         wlarc='${wl}'
-         _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
-         _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-         $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
-         ;;
-       esac
-      fi
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      case $host_os in
-      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
-      *)
-       # The compiler driver will combine and reorder linker options,
-       # but understands `-z linker_flag'.  GCC discards it without `$wl',
-       # but is careful enough not to reorder.
-       # Supported since Solaris 2.6 (maybe 2.5.1?)
-       if test "$GCC" = yes; then
-         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
-       else
-         _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
-       fi
-       ;;
-      esac
-      _LT_TAGVAR(link_all_deplibs, $1)=yes
-      ;;
-
-    sunos4*)
-      if test "x$host_vendor" = xsequent; then
-       # Use $CC to link under sequent, because it throws in some extra .o
-       # files that make .init and .fini sections work.
-       _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
-      else
-       _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
-      fi
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_minus_L, $1)=yes
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    sysv4)
-      case $host_vendor in
-       sni)
-         _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-         _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
-       ;;
-       siemens)
-         ## LD is ld it makes a PLAMLIB
-         ## CC just makes a GrossModule.
-         _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
-         _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
-         _LT_TAGVAR(hardcode_direct, $1)=no
-        ;;
-       motorola)
-         _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-         _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
-       ;;
-      esac
-      runpath_var='LD_RUN_PATH'
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    sysv4.3*)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
-      ;;
-
-    sysv4*MP*)
-      if test -d /usr/nec; then
-       _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-       runpath_var=LD_RUN_PATH
-       hardcode_runpath_var=yes
-       _LT_TAGVAR(ld_shlibs, $1)=yes
-      fi
-      ;;
-
-    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
-      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
-      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      runpath_var='LD_RUN_PATH'
-
-      if test "$GCC" = yes; then
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-      else
-       _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-      fi
-      ;;
-
-    sysv5* | sco3.2v5* | sco5v6*)
-      # Note: We can NOT use -z defs as we might desire, because we do not
-      # link with -lc, and that would cause any symbols used from libc to
-      # always be unresolved, which means just about no library would
-      # ever link correctly.  If we're not using GNU ld we use -z text
-      # though, which does catch some bad symbols but isn't as heavy-handed
-      # as -z defs.
-      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
-      _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
-      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
-      _LT_TAGVAR(link_all_deplibs, $1)=yes
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
-      runpath_var='LD_RUN_PATH'
-
-      if test "$GCC" = yes; then
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-      else
-       _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-      fi
-      ;;
-
-    uts4*)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    *)
-      _LT_TAGVAR(ld_shlibs, $1)=no
-      ;;
-    esac
-
-    if test x$host_vendor = xsni; then
-      case $host in
-      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
-       _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
-       ;;
-      esac
-    fi
-  fi
-])
-AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
-test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
-
-_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
-
-_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
-_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
-_LT_DECL([], [extract_expsyms_cmds], [2],
-    [The commands to extract the exported symbol list from a shared archive])
-
-#
-# Do we need to explicitly link libc?
-#
-case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
-x|xyes)
-  # Assume -lc should be added
-  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
-
-  if test "$enable_shared" = yes && test "$GCC" = yes; then
-    case $_LT_TAGVAR(archive_cmds, $1) in
-    *'~'*)
-      # FIXME: we may have to deal with multi-command sequences.
-      ;;
-    '$CC '*)
-      # Test whether the compiler implicitly links with -lc since on some
-      # systems, -lgcc has to come before -lc. If gcc already passes -lc
-      # to ld, don't add -lc before -lgcc.
-      AC_CACHE_CHECK([whether -lc should be explicitly linked in],
-       [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
-       [$RM conftest*
-       echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-
-       if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
-         soname=conftest
-         lib=conftest
-         libobjs=conftest.$ac_objext
-         deplibs=
-         wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
-         pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
-         compiler_flags=-v
-         linker_flags=-v
-         verstring=
-         output_objdir=.
-         libname=conftest
-         lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
-         _LT_TAGVAR(allow_undefined_flag, $1)=
-         if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
-         then
-           lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-         else
-           lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
-         fi
-         _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
-       else
-         cat conftest.err 1>&5
-       fi
-       $RM conftest*
-       ])
-      _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
-      ;;
-    esac
-  fi
-  ;;
-esac
-
-_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
-    [Whether or not to add -lc for building shared libraries])
-_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
-    [enable_shared_with_static_runtimes], [0],
-    [Whether or not to disallow shared libs when runtime libs are static])
-_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
-    [Compiler flag to allow reflexive dlopens])
-_LT_TAGDECL([], [whole_archive_flag_spec], [1],
-    [Compiler flag to generate shared objects directly from archives])
-_LT_TAGDECL([], [compiler_needs_object], [1],
-    [Whether the compiler copes with passing no objects directly])
-_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
-    [Create an old-style archive from a shared archive])
-_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
-    [Create a temporary old-style archive to link instead of a shared archive])
-_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
-_LT_TAGDECL([], [archive_expsym_cmds], [2])
-_LT_TAGDECL([], [module_cmds], [2],
-    [Commands used to build a loadable module if different from building
-    a shared archive.])
-_LT_TAGDECL([], [module_expsym_cmds], [2])
-_LT_TAGDECL([], [with_gnu_ld], [1],
-    [Whether we are building with GNU ld or not])
-_LT_TAGDECL([], [allow_undefined_flag], [1],
-    [Flag that allows shared libraries with undefined symbols to be built])
-_LT_TAGDECL([], [no_undefined_flag], [1],
-    [Flag that enforces no undefined symbols])
-_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
-    [Flag to hardcode $libdir into a binary during linking.
-    This must work even if $libdir does not exist])
-_LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1],
-    [[If ld is used when linking, flag to hardcode $libdir into a binary
-    during linking.  This must work even if $libdir does not exist]])
-_LT_TAGDECL([], [hardcode_libdir_separator], [1],
-    [Whether we need a single "-rpath" flag with a separated argument])
-_LT_TAGDECL([], [hardcode_direct], [0],
-    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
-    DIR into the resulting binary])
-_LT_TAGDECL([], [hardcode_direct_absolute], [0],
-    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
-    DIR into the resulting binary and the resulting library dependency is
-    "absolute", i.e impossible to change by setting ${shlibpath_var} if the
-    library is relocated])
-_LT_TAGDECL([], [hardcode_minus_L], [0],
-    [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
-    into the resulting binary])
-_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
-    [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
-    into the resulting binary])
-_LT_TAGDECL([], [hardcode_automatic], [0],
-    [Set to "yes" if building a shared library automatically hardcodes DIR
-    into the library and all subsequent libraries and executables linked
-    against it])
-_LT_TAGDECL([], [inherit_rpath], [0],
-    [Set to yes if linker adds runtime paths of dependent libraries
-    to runtime path list])
-_LT_TAGDECL([], [link_all_deplibs], [0],
-    [Whether libtool must link a program against all its dependency libraries])
-_LT_TAGDECL([], [always_export_symbols], [0],
-    [Set to "yes" if exported symbols are required])
-_LT_TAGDECL([], [export_symbols_cmds], [2],
-    [The commands to list exported symbols])
-_LT_TAGDECL([], [exclude_expsyms], [1],
-    [Symbols that should not be listed in the preloaded symbols])
-_LT_TAGDECL([], [include_expsyms], [1],
-    [Symbols that must always be exported])
-_LT_TAGDECL([], [prelink_cmds], [2],
-    [Commands necessary for linking programs (against libraries) with templates])
-_LT_TAGDECL([], [postlink_cmds], [2],
-    [Commands necessary for finishing linking programs])
-_LT_TAGDECL([], [file_list_spec], [1],
-    [Specify filename containing input files])
-dnl FIXME: Not yet implemented
-dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
-dnl    [Compiler flag to generate thread safe objects])
-])# _LT_LINKER_SHLIBS
-
-
-# _LT_LANG_C_CONFIG([TAG])
-# ------------------------
-# Ensure that the configuration variables for a C compiler are suitably
-# defined.  These variables are subsequently used by _LT_CONFIG to write
-# the compiler configuration to `libtool'.
-m4_defun([_LT_LANG_C_CONFIG],
-[m4_require([_LT_DECL_EGREP])dnl
-lt_save_CC="$CC"
-AC_LANG_PUSH(C)
-
-# Source file extension for C test sources.
-ac_ext=c
-
-# Object file extension for compiled C test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code="int some_variable = 0;"
-
-# Code to be used in simple link tests
-lt_simple_link_test_code='int main(){return(0);}'
-
-_LT_TAG_COMPILER
-# Save the default compiler, since it gets overwritten when the other
-# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
-compiler_DEFAULT=$CC
-
-# save warnings/boilerplate of simple test code
-_LT_COMPILER_BOILERPLATE
-_LT_LINKER_BOILERPLATE
-
-if test -n "$compiler"; then
-  _LT_COMPILER_NO_RTTI($1)
-  _LT_COMPILER_PIC($1)
-  _LT_COMPILER_C_O($1)
-  _LT_COMPILER_FILE_LOCKS($1)
-  _LT_LINKER_SHLIBS($1)
-  _LT_SYS_DYNAMIC_LINKER($1)
-  _LT_LINKER_HARDCODE_LIBPATH($1)
-  LT_SYS_DLOPEN_SELF
-  _LT_CMD_STRIPLIB
-
-  # Report which library types will actually be built
-  AC_MSG_CHECKING([if libtool supports shared libraries])
-  AC_MSG_RESULT([$can_build_shared])
-
-  AC_MSG_CHECKING([whether to build shared libraries])
-  test "$can_build_shared" = "no" && enable_shared=no
-
-  # On AIX, shared libraries and static libraries use the same namespace, and
-  # are all built from PIC.
-  case $host_os in
-  aix3*)
-    test "$enable_shared" = yes && enable_static=no
-    if test -n "$RANLIB"; then
-      archive_cmds="$archive_cmds~\$RANLIB \$lib"
-      postinstall_cmds='$RANLIB $lib'
-    fi
-    ;;
-
-  aix[[4-9]]*)
-    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
-      test "$enable_shared" = yes && enable_static=no
-    fi
-    ;;
-  esac
-  AC_MSG_RESULT([$enable_shared])
-
-  AC_MSG_CHECKING([whether to build static libraries])
-  # Make sure either enable_shared or enable_static is yes.
-  test "$enable_shared" = yes || enable_static=yes
-  AC_MSG_RESULT([$enable_static])
-
-  _LT_CONFIG($1)
-fi
-AC_LANG_POP
-CC="$lt_save_CC"
-])# _LT_LANG_C_CONFIG
-
-
-# _LT_LANG_CXX_CONFIG([TAG])
-# --------------------------
-# Ensure that the configuration variables for a C++ compiler are suitably
-# defined.  These variables are subsequently used by _LT_CONFIG to write
-# the compiler configuration to `libtool'.
-m4_defun([_LT_LANG_CXX_CONFIG],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_PATH_MANIFEST_TOOL])dnl
-if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
-    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
-    (test "X$CXX" != "Xg++"))) ; then
-  AC_PROG_CXXCPP
-else
-  _lt_caught_CXX_error=yes
-fi
-
-AC_LANG_PUSH(C++)
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-_LT_TAGVAR(allow_undefined_flag, $1)=
-_LT_TAGVAR(always_export_symbols, $1)=no
-_LT_TAGVAR(archive_expsym_cmds, $1)=
-_LT_TAGVAR(compiler_needs_object, $1)=no
-_LT_TAGVAR(export_dynamic_flag_spec, $1)=
-_LT_TAGVAR(hardcode_direct, $1)=no
-_LT_TAGVAR(hardcode_direct_absolute, $1)=no
-_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
-_LT_TAGVAR(hardcode_libdir_separator, $1)=
-_LT_TAGVAR(hardcode_minus_L, $1)=no
-_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
-_LT_TAGVAR(hardcode_automatic, $1)=no
-_LT_TAGVAR(inherit_rpath, $1)=no
-_LT_TAGVAR(module_cmds, $1)=
-_LT_TAGVAR(module_expsym_cmds, $1)=
-_LT_TAGVAR(link_all_deplibs, $1)=unknown
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-_LT_TAGVAR(no_undefined_flag, $1)=
-_LT_TAGVAR(whole_archive_flag_spec, $1)=
-_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
-
-# Source file extension for C++ test sources.
-ac_ext=cpp
-
-# Object file extension for compiled C++ test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# No sense in running all these tests if we already determined that
-# the CXX compiler isn't working.  Some variables (like enable_shared)
-# are currently assumed to apply to all compilers on this platform,
-# and will be corrupted by setting them based on a non-working compiler.
-if test "$_lt_caught_CXX_error" != yes; then
-  # Code to be used in simple compile tests
-  lt_simple_compile_test_code="int some_variable = 0;"
-
-  # Code to be used in simple link tests
-  lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
-
-  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
-  _LT_TAG_COMPILER
-
-  # save warnings/boilerplate of simple test code
-  _LT_COMPILER_BOILERPLATE
-  _LT_LINKER_BOILERPLATE
-
-  # Allow CC to be a program name with arguments.
-  lt_save_CC=$CC
-  lt_save_CFLAGS=$CFLAGS
-  lt_save_LD=$LD
-  lt_save_GCC=$GCC
-  GCC=$GXX
-  lt_save_with_gnu_ld=$with_gnu_ld
-  lt_save_path_LD=$lt_cv_path_LD
-  if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
-    lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
-  else
-    $as_unset lt_cv_prog_gnu_ld
-  fi
-  if test -n "${lt_cv_path_LDCXX+set}"; then
-    lt_cv_path_LD=$lt_cv_path_LDCXX
-  else
-    $as_unset lt_cv_path_LD
-  fi
-  test -z "${LDCXX+set}" || LD=$LDCXX
-  CC=${CXX-"c++"}
-  CFLAGS=$CXXFLAGS
-  compiler=$CC
-  _LT_TAGVAR(compiler, $1)=$CC
-  _LT_CC_BASENAME([$compiler])
-
-  if test -n "$compiler"; then
-    # We don't want -fno-exception when compiling C++ code, so set the
-    # no_builtin_flag separately
-    if test "$GXX" = yes; then
-      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
-    else
-      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
-    fi
-
-    if test "$GXX" = yes; then
-      # Set up default GNU C++ configuration
-
-      LT_PATH_LD
-
-      # Check if GNU C++ uses GNU ld as the underlying linker, since the
-      # archiving commands below assume that GNU ld is being used.
-      if test "$with_gnu_ld" = yes; then
-        _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
-        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
-
-        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
-
-        # If archive_cmds runs LD, not CC, wlarc should be empty
-        # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
-        #     investigate it a little bit more. (MM)
-        wlarc='${wl}'
-
-        # ancient GNU ld didn't support --whole-archive et. al.
-        if eval "`$CC -print-prog-name=ld` --help 2>&1" |
-         $GREP 'no-whole-archive' > /dev/null; then
-          _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
-        else
-          _LT_TAGVAR(whole_archive_flag_spec, $1)=
-        fi
-      else
-        with_gnu_ld=no
-        wlarc=
-
-        # A generic and very simple default shared library creation
-        # command for GNU C++ for the case where it uses the native
-        # linker, instead of GNU ld.  If possible, this setting should
-        # overridden to take advantage of the native linker features on
-        # the platform it is being used on.
-        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
-      fi
-
-      # Commands to make compiler produce verbose output that lists
-      # what "hidden" libraries, object files and flags are used when
-      # linking a shared library.
-      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
-
-    else
-      GXX=no
-      with_gnu_ld=no
-      wlarc=
-    fi
-
-    # PORTME: fill in a description of your system's C++ link characteristics
-    AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
-    _LT_TAGVAR(ld_shlibs, $1)=yes
-    case $host_os in
-      aix3*)
-        # FIXME: insert proper C++ library support
-        _LT_TAGVAR(ld_shlibs, $1)=no
-        ;;
-      aix[[4-9]]*)
-        if test "$host_cpu" = ia64; then
-          # On IA64, the linker does run time linking by default, so we don't
-          # have to do anything special.
-          aix_use_runtimelinking=no
-          exp_sym_flag='-Bexport'
-          no_entry_flag=""
-        else
-          aix_use_runtimelinking=no
-
-          # Test if we are trying to use run time linking or normal
-          # AIX style linking. If -brtl is somewhere in LDFLAGS, we
-          # need to do runtime linking.
-          case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
-           for ld_flag in $LDFLAGS; do
-             case $ld_flag in
-             *-brtl*)
-               aix_use_runtimelinking=yes
-               break
-               ;;
-             esac
-           done
-           ;;
-          esac
-
-          exp_sym_flag='-bexport'
-          no_entry_flag='-bnoentry'
-        fi
-
-        # When large executables or shared objects are built, AIX ld can
-        # have problems creating the table of contents.  If linking a library
-        # or program results in "error TOC overflow" add -mminimal-toc to
-        # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
-        # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
-
-        _LT_TAGVAR(archive_cmds, $1)=''
-        _LT_TAGVAR(hardcode_direct, $1)=yes
-        _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-        _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
-        _LT_TAGVAR(link_all_deplibs, $1)=yes
-        _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
-
-        if test "$GXX" = yes; then
-          case $host_os in aix4.[[012]]|aix4.[[012]].*)
-          # We only want to do this on AIX 4.2 and lower, the check
-          # below for broken collect2 doesn't work under 4.3+
-         collect2name=`${CC} -print-prog-name=collect2`
-         if test -f "$collect2name" &&
-            strings "$collect2name" | $GREP resolve_lib_name >/dev/null
-         then
-           # We have reworked collect2
-           :
-         else
-           # We have old collect2
-           _LT_TAGVAR(hardcode_direct, $1)=unsupported
-           # It fails to find uninstalled libraries when the uninstalled
-           # path is not listed in the libpath.  Setting hardcode_minus_L
-           # to unsupported forces relinking
-           _LT_TAGVAR(hardcode_minus_L, $1)=yes
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-           _LT_TAGVAR(hardcode_libdir_separator, $1)=
-         fi
-          esac
-          shared_flag='-shared'
-         if test "$aix_use_runtimelinking" = yes; then
-           shared_flag="$shared_flag "'${wl}-G'
-         fi
-        else
-          # not using gcc
-          if test "$host_cpu" = ia64; then
-         # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
-         # chokes on -Wl,-G. The following line is correct:
-         shared_flag='-G'
-          else
-           if test "$aix_use_runtimelinking" = yes; then
-             shared_flag='${wl}-G'
-           else
-             shared_flag='${wl}-bM:SRE'
-           fi
-          fi
-        fi
-
-        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
-        # It seems that -bexpall does not export symbols beginning with
-        # underscore (_), so it is better to generate a list of symbols to
-       # export.
-        _LT_TAGVAR(always_export_symbols, $1)=yes
-        if test "$aix_use_runtimelinking" = yes; then
-          # Warning - without using the other runtime loading flags (-brtl),
-          # -berok will link without error, but may produce a broken library.
-          _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
-          # Determine the default libpath from the value encoded in an empty
-          # executable.
-          _LT_SYS_MODULE_PATH_AIX([$1])
-          _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
-
-          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
-        else
-          if test "$host_cpu" = ia64; then
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
-           _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
-           _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
-          else
-           # Determine the default libpath from the value encoded in an
-           # empty executable.
-           _LT_SYS_MODULE_PATH_AIX([$1])
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
-           # Warning - without using the other run time loading flags,
-           # -berok will link without error, but may produce a broken library.
-           _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
-           _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
-           if test "$with_gnu_ld" = yes; then
-             # We only use this code for GNU lds that support --whole-archive.
-             _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
-           else
-             # Exported symbols can be pulled into shared objects from archives
-             _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
-           fi
-           _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
-           # This is similar to how AIX traditionally builds its shared
-           # libraries.
-           _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
-          fi
-        fi
-        ;;
-
-      beos*)
-       if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-         _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-         # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
-         # support --undefined.  This deserves some investigation.  FIXME
-         _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-       else
-         _LT_TAGVAR(ld_shlibs, $1)=no
-       fi
-       ;;
-
-      chorus*)
-        case $cc_basename in
-          *)
-         # FIXME: insert proper C++ library support
-         _LT_TAGVAR(ld_shlibs, $1)=no
-         ;;
-        esac
-        ;;
-
-      cygwin* | mingw* | pw32* | cegcc*)
-       case $GXX,$cc_basename in
-       ,cl* | no,cl*)
-         # Native MSVC
-         # hardcode_libdir_flag_spec is actually meaningless, as there is
-         # no search path for DLLs.
-         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
-         _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-         _LT_TAGVAR(always_export_symbols, $1)=yes
-         _LT_TAGVAR(file_list_spec, $1)='@'
-         # Tell ltmain to make .lib files, not .a files.
-         libext=lib
-         # Tell ltmain to make .dll files, not .so files.
-         shrext_cmds=".dll"
-         # FIXME: Setting linknames here is a bad hack.
-         _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
-         _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
-             $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
-           else
-             $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
-           fi~
-           $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
-           linknames='
-         # The linker will not automatically build a static lib if we build a DLL.
-         # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
-         _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-         # Don't use ranlib
-         _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
-         _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
-           lt_tool_outputfile="@TOOL_OUTPUT@"~
-           case $lt_outputfile in
-             *.exe|*.EXE) ;;
-             *)
-               lt_outputfile="$lt_outputfile.exe"
-               lt_tool_outputfile="$lt_tool_outputfile.exe"
-               ;;
-           esac~
-           func_to_tool_file "$lt_outputfile"~
-           if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
-             $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
-             $RM "$lt_outputfile.manifest";
-           fi'
-         ;;
-       *)
-         # g++
-         # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
-         # as there is no search path for DLLs.
-         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-         _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
-         _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-         _LT_TAGVAR(always_export_symbols, $1)=no
-         _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-
-         if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
-           _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
-           # If the export-symbols file already is a .def file (1st line
-           # is EXPORTS), use it as is; otherwise, prepend...
-           _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
-             cp $export_symbols $output_objdir/$soname.def;
-           else
-             echo EXPORTS > $output_objdir/$soname.def;
-             cat $export_symbols >> $output_objdir/$soname.def;
-           fi~
-           $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
-         else
-           _LT_TAGVAR(ld_shlibs, $1)=no
-         fi
-         ;;
-       esac
-       ;;
-      darwin* | rhapsody*)
-        _LT_DARWIN_LINKER_FEATURES($1)
-       ;;
-
-      dgux*)
-        case $cc_basename in
-          ec++*)
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-          ghcx*)
-           # Green Hills C++ Compiler
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-          *)
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-        esac
-        ;;
-
-      freebsd[[12]]*)
-        # C++ shared libraries reported to be fairly broken before
-       # switch to ELF
-        _LT_TAGVAR(ld_shlibs, $1)=no
-        ;;
-
-      freebsd-elf*)
-        _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-        ;;
-
-      freebsd* | dragonfly*)
-        # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
-        # conventions
-        _LT_TAGVAR(ld_shlibs, $1)=yes
-        ;;
-
-      gnu*)
-        ;;
-
-      haiku*)
-        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-        _LT_TAGVAR(link_all_deplibs, $1)=yes
-        ;;
-
-      hpux9*)
-        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
-        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
-        _LT_TAGVAR(hardcode_direct, $1)=yes
-        _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
-                                            # but as the default
-                                            # location of the library.
-
-        case $cc_basename in
-          CC*)
-            # FIXME: insert proper C++ library support
-            _LT_TAGVAR(ld_shlibs, $1)=no
-            ;;
-          aCC*)
-            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
-            # Commands to make compiler produce verbose output that lists
-            # what "hidden" libraries, object files and flags are used when
-            # linking a shared library.
-            #
-            # There doesn't appear to be a way to prevent this compiler from
-            # explicitly linking system object files so we need to strip them
-            # from the output so that they don't get included in the library
-            # dependencies.
-            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
-            ;;
-          *)
-            if test "$GXX" = yes; then
-              _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
-            else
-              # FIXME: insert proper C++ library support
-              _LT_TAGVAR(ld_shlibs, $1)=no
-            fi
-            ;;
-        esac
-        ;;
-
-      hpux10*|hpux11*)
-        if test $with_gnu_ld = no; then
-         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
-         _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
-          case $host_cpu in
-            hppa*64*|ia64*)
-              ;;
-            *)
-             _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
-              ;;
-          esac
-        fi
-        case $host_cpu in
-          hppa*64*|ia64*)
-            _LT_TAGVAR(hardcode_direct, $1)=no
-            _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-            ;;
-          *)
-            _LT_TAGVAR(hardcode_direct, $1)=yes
-            _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-            _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
-                                                # but as the default
-                                                # location of the library.
-            ;;
-        esac
-
-        case $cc_basename in
-          CC*)
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-          aCC*)
-           case $host_cpu in
-             hppa*64*)
-               _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-               ;;
-             ia64*)
-               _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-               ;;
-             *)
-               _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-               ;;
-           esac
-           # Commands to make compiler produce verbose output that lists
-           # what "hidden" libraries, object files and flags are used when
-           # linking a shared library.
-           #
-           # There doesn't appear to be a way to prevent this compiler from
-           # explicitly linking system object files so we need to strip them
-           # from the output so that they don't get included in the library
-           # dependencies.
-           output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
-           ;;
-          *)
-           if test "$GXX" = yes; then
-             if test $with_gnu_ld = no; then
-               case $host_cpu in
-                 hppa*64*)
-                   _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-                   ;;
-                 ia64*)
-                   _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-                   ;;
-                 *)
-                   _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-                   ;;
-               esac
-             fi
-           else
-             # FIXME: insert proper C++ library support
-             _LT_TAGVAR(ld_shlibs, $1)=no
-           fi
-           ;;
-        esac
-        ;;
-
-      interix[[3-9]]*)
-       _LT_TAGVAR(hardcode_direct, $1)=no
-       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-       _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
-       # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
-       # Instead, shared libraries are loaded at an image base (0x10000000 by
-       # default) and relocated if they conflict, which is a slow very memory
-       # consuming and fragmenting process.  To avoid this, we pick a random,
-       # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
-       # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
-       ;;
-      irix5* | irix6*)
-        case $cc_basename in
-          CC*)
-           # SGI C++
-           _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
-
-           # Archives containing C++ object files must be created using
-           # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
-           # necessary to make sure instantiated templates are included
-           # in the archive.
-           _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
-           ;;
-          *)
-           if test "$GXX" = yes; then
-             if test "$with_gnu_ld" = no; then
-               _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
-             else
-               _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
-             fi
-           fi
-           _LT_TAGVAR(link_all_deplibs, $1)=yes
-           ;;
-        esac
-        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-        _LT_TAGVAR(inherit_rpath, $1)=yes
-        ;;
-
-      linux* | k*bsd*-gnu | kopensolaris*-gnu)
-        case $cc_basename in
-          KCC*)
-           # Kuck and Associates, Inc. (KAI) C++ Compiler
-
-           # KCC will only create a shared library if the output file
-           # ends with ".so" (or ".sl" for HP-UX), so rename the library
-           # to its proper name (with version) after linking.
-           _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
-           _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
-           # Commands to make compiler produce verbose output that lists
-           # what "hidden" libraries, object files and flags are used when
-           # linking a shared library.
-           #
-           # There doesn't appear to be a way to prevent this compiler from
-           # explicitly linking system object files so we need to strip them
-           # from the output so that they don't get included in the library
-           # dependencies.
-           output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
-
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-           _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
-
-           # Archives containing C++ object files must be created using
-           # "CC -Bstatic", where "CC" is the KAI C++ compiler.
-           _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
-           ;;
-         icpc* | ecpc* )
-           # Intel C++
-           with_gnu_ld=yes
-           # version 8.0 and above of icpc choke on multiply defined symbols
-           # if we add $predep_objects and $postdep_objects, however 7.1 and
-           # earlier do not add the objects themselves.
-           case `$CC -V 2>&1` in
-             *"Version 7."*)
-               _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
-               _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
-               ;;
-             *)  # Version 8.0 or newer
-               tmp_idyn=
-               case $host_cpu in
-                 ia64*) tmp_idyn=' -i_dynamic';;
-               esac
-               _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-               _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
-               ;;
-           esac
-           _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-           _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
-           _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
-           ;;
-          pgCC* | pgcpp*)
-            # Portland Group C++ compiler
-           case `$CC -V` in
-           *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
-             _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
-               rm -rf $tpldir~
-               $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
-               compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
-             _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
-               rm -rf $tpldir~
-               $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
-               $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
-               $RANLIB $oldlib'
-             _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
-               rm -rf $tpldir~
-               $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
-               $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
-             _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
-               rm -rf $tpldir~
-               $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
-               $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
-             ;;
-           *) # Version 6 and above use weak symbols
-             _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
-             _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
-             ;;
-           esac
-
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
-           _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
-           _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
-            ;;
-         cxx*)
-           # Compaq C++
-           _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
-           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
-
-           runpath_var=LD_RUN_PATH
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
-           _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
-           # Commands to make compiler produce verbose output that lists
-           # what "hidden" libraries, object files and flags are used when
-           # linking a shared library.
-           #
-           # There doesn't appear to be a way to prevent this compiler from
-           # explicitly linking system object files so we need to strip them
-           # from the output so that they don't get included in the library
-           # dependencies.
-           output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
-           ;;
-         xl* | mpixl* | bgxl*)
-           # IBM XL 8.0 on PPC, with GNU ld
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-           _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
-           _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-           if test "x$supports_anon_versioning" = xyes; then
-             _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
-               cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-               echo "local: *; };" >> $output_objdir/$libname.ver~
-               $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
-           fi
-           ;;
-         *)
-           case `$CC -V 2>&1 | sed 5q` in
-           *Sun\ C*)
-             # Sun C++ 5.9
-             _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
-             _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-             _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
-             _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-             _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
-             _LT_TAGVAR(compiler_needs_object, $1)=yes
-
-             # Not sure whether something based on
-             # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
-             # would be better.
-             output_verbose_link_cmd='func_echo_all'
-
-             # Archives containing C++ object files must be created using
-             # "CC -xar", where "CC" is the Sun C++ compiler.  This is
-             # necessary to make sure instantiated templates are included
-             # in the archive.
-             _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
-             ;;
-           esac
-           ;;
-       esac
-       ;;
-
-      lynxos*)
-        # FIXME: insert proper C++ library support
-       _LT_TAGVAR(ld_shlibs, $1)=no
-       ;;
-
-      m88k*)
-        # FIXME: insert proper C++ library support
-        _LT_TAGVAR(ld_shlibs, $1)=no
-       ;;
-
-      mvs*)
-        case $cc_basename in
-          cxx*)
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-         *)
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-       esac
-       ;;
-
-      netbsd*)
-        if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
-         _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
-         wlarc=
-         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-         _LT_TAGVAR(hardcode_direct, $1)=yes
-         _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-       fi
-       # Workaround some broken pre-1.5 toolchains
-       output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
-       ;;
-
-      *nto* | *qnx*)
-        _LT_TAGVAR(ld_shlibs, $1)=yes
-       ;;
-
-      openbsd2*)
-        # C++ shared libraries are fairly broken
-       _LT_TAGVAR(ld_shlibs, $1)=no
-       ;;
-
-      openbsd*)
-       if test -f /usr/libexec/ld.so; then
-         _LT_TAGVAR(hardcode_direct, $1)=yes
-         _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-         _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
-         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-         if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
-           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
-           _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
-           _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
-         fi
-         output_verbose_link_cmd=func_echo_all
-       else
-         _LT_TAGVAR(ld_shlibs, $1)=no
-       fi
-       ;;
-
-      osf3* | osf4* | osf5*)
-        case $cc_basename in
-          KCC*)
-           # Kuck and Associates, Inc. (KAI) C++ Compiler
-
-           # KCC will only create a shared library if the output file
-           # ends with ".so" (or ".sl" for HP-UX), so rename the library
-           # to its proper name (with version) after linking.
-           _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
-
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-           _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
-           # Archives containing C++ object files must be created using
-           # the KAI C++ compiler.
-           case $host in
-             osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
-             *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
-           esac
-           ;;
-          RCC*)
-           # Rational C++ 2.4.1
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-          cxx*)
-           case $host in
-             osf3*)
-               _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
-               _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
-               _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-               ;;
-             *)
-               _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
-               _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
-               _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
-                 echo "-hidden">> $lib.exp~
-                 $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp  `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
-                 $RM $lib.exp'
-               _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
-               ;;
-           esac
-
-           _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
-           # Commands to make compiler produce verbose output that lists
-           # what "hidden" libraries, object files and flags are used when
-           # linking a shared library.
-           #
-           # There doesn't appear to be a way to prevent this compiler from
-           # explicitly linking system object files so we need to strip them
-           # from the output so that they don't get included in the library
-           # dependencies.
-           output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
-           ;;
-         *)
-           if test "$GXX" = yes && test "$with_gnu_ld" = no; then
-             _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
-             case $host in
-               osf3*)
-                 _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
-                 ;;
-               *)
-                 _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
-                 ;;
-             esac
-
-             _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-             _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
-             # Commands to make compiler produce verbose output that lists
-             # what "hidden" libraries, object files and flags are used when
-             # linking a shared library.
-             output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
-
-           else
-             # FIXME: insert proper C++ library support
-             _LT_TAGVAR(ld_shlibs, $1)=no
-           fi
-           ;;
-        esac
-        ;;
-
-      psos*)
-        # FIXME: insert proper C++ library support
-        _LT_TAGVAR(ld_shlibs, $1)=no
-        ;;
-
-      sunos4*)
-        case $cc_basename in
-          CC*)
-           # Sun C++ 4.x
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-          lcc*)
-           # Lucid
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-          *)
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-        esac
-        ;;
-
-      solaris*)
-        case $cc_basename in
-          CC* | sunCC*)
-           # Sun C++ 4.2, 5.x and Centerline C++
-            _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
-           _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
-           _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-           _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-             $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
-
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-           _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-           case $host_os in
-             solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
-             *)
-               # The compiler driver will combine and reorder linker options,
-               # but understands `-z linker_flag'.
-               # Supported since Solaris 2.6 (maybe 2.5.1?)
-               _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
-               ;;
-           esac
-           _LT_TAGVAR(link_all_deplibs, $1)=yes
-
-           output_verbose_link_cmd='func_echo_all'
-
-           # Archives containing C++ object files must be created using
-           # "CC -xar", where "CC" is the Sun C++ compiler.  This is
-           # necessary to make sure instantiated templates are included
-           # in the archive.
-           _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
-           ;;
-          gcx*)
-           # Green Hills C++ Compiler
-           _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
-
-           # The C++ compiler must be used to create the archive.
-           _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
-           ;;
-          *)
-           # GNU C++ compiler with Solaris linker
-           if test "$GXX" = yes && test "$with_gnu_ld" = no; then
-             _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
-             if $CC --version | $GREP -v '^2\.7' > /dev/null; then
-               _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
-               _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-                 $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
-
-               # Commands to make compiler produce verbose output that lists
-               # what "hidden" libraries, object files and flags are used when
-               # linking a shared library.
-               output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
-             else
-               # g++ 2.7 appears to require `-G' NOT `-shared' on this
-               # platform.
-               _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
-               _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-                 $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
-
-               # Commands to make compiler produce verbose output that lists
-               # what "hidden" libraries, object files and flags are used when
-               # linking a shared library.
-               output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
-             fi
-
-             _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
-             case $host_os in
-               solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
-               *)
-                 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
-                 ;;
-             esac
-           fi
-           ;;
-        esac
-        ;;
-
-    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
-      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
-      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      runpath_var='LD_RUN_PATH'
-
-      case $cc_basename in
-        CC*)
-         _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-         _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-         ;;
-       *)
-         _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-         _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-         ;;
-      esac
-      ;;
-
-      sysv5* | sco3.2v5* | sco5v6*)
-       # Note: We can NOT use -z defs as we might desire, because we do not
-       # link with -lc, and that would cause any symbols used from libc to
-       # always be unresolved, which means just about no library would
-       # ever link correctly.  If we're not using GNU ld we use -z text
-       # though, which does catch some bad symbols but isn't as heavy-handed
-       # as -z defs.
-       _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
-       _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
-       _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
-       _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
-       _LT_TAGVAR(link_all_deplibs, $1)=yes
-       _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
-       runpath_var='LD_RUN_PATH'
-
-       case $cc_basename in
-          CC*)
-           _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-           _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
-             '"$_LT_TAGVAR(old_archive_cmds, $1)"
-           _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
-             '"$_LT_TAGVAR(reload_cmds, $1)"
-           ;;
-         *)
-           _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-           ;;
-       esac
-      ;;
-
-      tandem*)
-        case $cc_basename in
-          NCC*)
-           # NonStop-UX NCC 3.20
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-          *)
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-        esac
-        ;;
-
-      vxworks*)
-        # FIXME: insert proper C++ library support
-        _LT_TAGVAR(ld_shlibs, $1)=no
-        ;;
-
-      *)
-        # FIXME: insert proper C++ library support
-        _LT_TAGVAR(ld_shlibs, $1)=no
-        ;;
-    esac
-
-    AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
-    test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
-
-    _LT_TAGVAR(GCC, $1)="$GXX"
-    _LT_TAGVAR(LD, $1)="$LD"
-
-    ## CAVEAT EMPTOR:
-    ## There is no encapsulation within the following macros, do not change
-    ## the running order or otherwise move them around unless you know exactly
-    ## what you are doing...
-    _LT_SYS_HIDDEN_LIBDEPS($1)
-    _LT_COMPILER_PIC($1)
-    _LT_COMPILER_C_O($1)
-    _LT_COMPILER_FILE_LOCKS($1)
-    _LT_LINKER_SHLIBS($1)
-    _LT_SYS_DYNAMIC_LINKER($1)
-    _LT_LINKER_HARDCODE_LIBPATH($1)
-
-    _LT_CONFIG($1)
-  fi # test -n "$compiler"
-
-  CC=$lt_save_CC
-  CFLAGS=$lt_save_CFLAGS
-  LDCXX=$LD
-  LD=$lt_save_LD
-  GCC=$lt_save_GCC
-  with_gnu_ld=$lt_save_with_gnu_ld
-  lt_cv_path_LDCXX=$lt_cv_path_LD
-  lt_cv_path_LD=$lt_save_path_LD
-  lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
-  lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
-fi # test "$_lt_caught_CXX_error" != yes
-
-AC_LANG_POP
-])# _LT_LANG_CXX_CONFIG
-
-
-# _LT_FUNC_STRIPNAME_CNF
-# ----------------------
-# func_stripname_cnf prefix suffix name
-# strip PREFIX and SUFFIX off of NAME.
-# PREFIX and SUFFIX must not contain globbing or regex special
-# characters, hashes, percent signs, but SUFFIX may contain a leading
-# dot (in which case that matches only a dot).
-#
-# This function is identical to the (non-XSI) version of func_stripname,
-# except this one can be used by m4 code that may be executed by configure,
-# rather than the libtool script.
-m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
-AC_REQUIRE([_LT_DECL_SED])
-AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
-func_stripname_cnf ()
-{
-  case ${2} in
-  .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
-  *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
-  esac
-} # func_stripname_cnf
-])# _LT_FUNC_STRIPNAME_CNF
-
-# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
-# ---------------------------------
-# Figure out "hidden" library dependencies from verbose
-# compiler output when linking a shared library.
-# Parse the compiler output and extract the necessary
-# objects, libraries and library flags.
-m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
-# Dependencies to place before and after the object being linked:
-_LT_TAGVAR(predep_objects, $1)=
-_LT_TAGVAR(postdep_objects, $1)=
-_LT_TAGVAR(predeps, $1)=
-_LT_TAGVAR(postdeps, $1)=
-_LT_TAGVAR(compiler_lib_search_path, $1)=
-
-dnl we can't use the lt_simple_compile_test_code here,
-dnl because it contains code intended for an executable,
-dnl not a library.  It's possible we should let each
-dnl tag define a new lt_????_link_test_code variable,
-dnl but it's only used here...
-m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
-int a;
-void foo (void) { a = 0; }
-_LT_EOF
-], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
-class Foo
-{
-public:
-  Foo (void) { a = 0; }
-private:
-  int a;
-};
-_LT_EOF
-], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
-      subroutine foo
-      implicit none
-      integer*4 a
-      a=0
-      return
-      end
-_LT_EOF
-], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
-      subroutine foo
-      implicit none
-      integer a
-      a=0
-      return
-      end
-_LT_EOF
-], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
-public class foo {
-  private int a;
-  public void bar (void) {
-    a = 0;
-  }
-};
-_LT_EOF
-])
-
-_lt_libdeps_save_CFLAGS=$CFLAGS
-case "$CC $CFLAGS " in #(
-*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
-*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
-esac
-
-dnl Parse the compiler output and extract the necessary
-dnl objects, libraries and library flags.
-if AC_TRY_EVAL(ac_compile); then
-  # Parse the compiler output and extract the necessary
-  # objects, libraries and library flags.
-
-  # Sentinel used to keep track of whether or not we are before
-  # the conftest object file.
-  pre_test_object_deps_done=no
-
-  for p in `eval "$output_verbose_link_cmd"`; do
-    case ${prev}${p} in
-
-    -L* | -R* | -l*)
-       # Some compilers place space between "-{L,R}" and the path.
-       # Remove the space.
-       if test $p = "-L" ||
-          test $p = "-R"; then
-        prev=$p
-        continue
-       fi
-
-       # Expand the sysroot to ease extracting the directories later.
-       if test -z "$prev"; then
-         case $p in
-         -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
-         -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
-         -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
-         esac
-       fi
-       case $p in
-       =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
-       esac
-       if test "$pre_test_object_deps_done" = no; then
-        case ${prev} in
-        -L | -R)
-          # Internal compiler library paths should come after those
-          # provided the user.  The postdeps already come after the
-          # user supplied libs so there is no need to process them.
-          if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
-            _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
-          else
-            _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
-          fi
-          ;;
-        # The "-l" case would never come before the object being
-        # linked, so don't bother handling this case.
-        esac
-       else
-        if test -z "$_LT_TAGVAR(postdeps, $1)"; then
-          _LT_TAGVAR(postdeps, $1)="${prev}${p}"
-        else
-          _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
-        fi
-       fi
-       prev=
-       ;;
-
-    *.lto.$objext) ;; # Ignore GCC LTO objects
-    *.$objext)
-       # This assumes that the test object file only shows up
-       # once in the compiler output.
-       if test "$p" = "conftest.$objext"; then
-        pre_test_object_deps_done=yes
-        continue
-       fi
-
-       if test "$pre_test_object_deps_done" = no; then
-        if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
-          _LT_TAGVAR(predep_objects, $1)="$p"
-        else
-          _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
-        fi
-       else
-        if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
-          _LT_TAGVAR(postdep_objects, $1)="$p"
-        else
-          _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
-        fi
-       fi
-       ;;
-
-    *) ;; # Ignore the rest.
-
-    esac
-  done
-
-  # Clean up.
-  rm -f a.out a.exe
-else
-  echo "libtool.m4: error: problem compiling $1 test program"
-fi
-
-$RM -f confest.$objext
-CFLAGS=$_lt_libdeps_save_CFLAGS
-
-# PORTME: override above test on systems where it is broken
-m4_if([$1], [CXX],
-[case $host_os in
-interix[[3-9]]*)
-  # Interix 3.5 installs completely hosed .la files for C++, so rather than
-  # hack all around it, let's just trust "g++" to DTRT.
-  _LT_TAGVAR(predep_objects,$1)=
-  _LT_TAGVAR(postdep_objects,$1)=
-  _LT_TAGVAR(postdeps,$1)=
-  ;;
-
-linux*)
-  case `$CC -V 2>&1 | sed 5q` in
-  *Sun\ C*)
-    # Sun C++ 5.9
-
-    # The more standards-conforming stlport4 library is
-    # incompatible with the Cstd library. Avoid specifying
-    # it if it's in CXXFLAGS. Ignore libCrun as
-    # -library=stlport4 depends on it.
-    case " $CXX $CXXFLAGS " in
-    *" -library=stlport4 "*)
-      solaris_use_stlport4=yes
-      ;;
-    esac
-
-    if test "$solaris_use_stlport4" != yes; then
-      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
-    fi
-    ;;
-  esac
-  ;;
-
-solaris*)
-  case $cc_basename in
-  CC* | sunCC*)
-    # The more standards-conforming stlport4 library is
-    # incompatible with the Cstd library. Avoid specifying
-    # it if it's in CXXFLAGS. Ignore libCrun as
-    # -library=stlport4 depends on it.
-    case " $CXX $CXXFLAGS " in
-    *" -library=stlport4 "*)
-      solaris_use_stlport4=yes
-      ;;
-    esac
-
-    # Adding this requires a known-good setup of shared libraries for
-    # Sun compiler versions before 5.6, else PIC objects from an old
-    # archive will be linked into the output, leading to subtle bugs.
-    if test "$solaris_use_stlport4" != yes; then
-      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
-    fi
-    ;;
-  esac
-  ;;
-esac
-])
-
-case " $_LT_TAGVAR(postdeps, $1) " in
-*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
-esac
- _LT_TAGVAR(compiler_lib_search_dirs, $1)=
-if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
- _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
-fi
-_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
-    [The directories searched by this compiler when creating a shared library])
-_LT_TAGDECL([], [predep_objects], [1],
-    [Dependencies to place before and after the objects being linked to
-    create a shared library])
-_LT_TAGDECL([], [postdep_objects], [1])
-_LT_TAGDECL([], [predeps], [1])
-_LT_TAGDECL([], [postdeps], [1])
-_LT_TAGDECL([], [compiler_lib_search_path], [1],
-    [The library search path used internally by the compiler when linking
-    a shared library])
-])# _LT_SYS_HIDDEN_LIBDEPS
-
-
-# _LT_LANG_F77_CONFIG([TAG])
-# --------------------------
-# Ensure that the configuration variables for a Fortran 77 compiler are
-# suitably defined.  These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
-m4_defun([_LT_LANG_F77_CONFIG],
-[AC_LANG_PUSH(Fortran 77)
-if test -z "$F77" || test "X$F77" = "Xno"; then
-  _lt_disable_F77=yes
-fi
-
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-_LT_TAGVAR(allow_undefined_flag, $1)=
-_LT_TAGVAR(always_export_symbols, $1)=no
-_LT_TAGVAR(archive_expsym_cmds, $1)=
-_LT_TAGVAR(export_dynamic_flag_spec, $1)=
-_LT_TAGVAR(hardcode_direct, $1)=no
-_LT_TAGVAR(hardcode_direct_absolute, $1)=no
-_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
-_LT_TAGVAR(hardcode_libdir_separator, $1)=
-_LT_TAGVAR(hardcode_minus_L, $1)=no
-_LT_TAGVAR(hardcode_automatic, $1)=no
-_LT_TAGVAR(inherit_rpath, $1)=no
-_LT_TAGVAR(module_cmds, $1)=
-_LT_TAGVAR(module_expsym_cmds, $1)=
-_LT_TAGVAR(link_all_deplibs, $1)=unknown
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-_LT_TAGVAR(no_undefined_flag, $1)=
-_LT_TAGVAR(whole_archive_flag_spec, $1)=
-_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
-
-# Source file extension for f77 test sources.
-ac_ext=f
-
-# Object file extension for compiled f77 test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# No sense in running all these tests if we already determined that
-# the F77 compiler isn't working.  Some variables (like enable_shared)
-# are currently assumed to apply to all compilers on this platform,
-# and will be corrupted by setting them based on a non-working compiler.
-if test "$_lt_disable_F77" != yes; then
-  # Code to be used in simple compile tests
-  lt_simple_compile_test_code="\
-      subroutine t
-      return
-      end
-"
-
-  # Code to be used in simple link tests
-  lt_simple_link_test_code="\
-      program t
-      end
-"
-
-  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
-  _LT_TAG_COMPILER
-
-  # save warnings/boilerplate of simple test code
-  _LT_COMPILER_BOILERPLATE
-  _LT_LINKER_BOILERPLATE
-
-  # Allow CC to be a program name with arguments.
-  lt_save_CC="$CC"
-  lt_save_GCC=$GCC
-  lt_save_CFLAGS=$CFLAGS
-  CC=${F77-"f77"}
-  CFLAGS=$FFLAGS
-  compiler=$CC
-  _LT_TAGVAR(compiler, $1)=$CC
-  _LT_CC_BASENAME([$compiler])
-  GCC=$G77
-  if test -n "$compiler"; then
-    AC_MSG_CHECKING([if libtool supports shared libraries])
-    AC_MSG_RESULT([$can_build_shared])
-
-    AC_MSG_CHECKING([whether to build shared libraries])
-    test "$can_build_shared" = "no" && enable_shared=no
-
-    # On AIX, shared libraries and static libraries use the same namespace, and
-    # are all built from PIC.
-    case $host_os in
-      aix3*)
-        test "$enable_shared" = yes && enable_static=no
-        if test -n "$RANLIB"; then
-          archive_cmds="$archive_cmds~\$RANLIB \$lib"
-          postinstall_cmds='$RANLIB $lib'
-        fi
-        ;;
-      aix[[4-9]]*)
-       if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
-         test "$enable_shared" = yes && enable_static=no
-       fi
-        ;;
-    esac
-    AC_MSG_RESULT([$enable_shared])
-
-    AC_MSG_CHECKING([whether to build static libraries])
-    # Make sure either enable_shared or enable_static is yes.
-    test "$enable_shared" = yes || enable_static=yes
-    AC_MSG_RESULT([$enable_static])
-
-    _LT_TAGVAR(GCC, $1)="$G77"
-    _LT_TAGVAR(LD, $1)="$LD"
-
-    ## CAVEAT EMPTOR:
-    ## There is no encapsulation within the following macros, do not change
-    ## the running order or otherwise move them around unless you know exactly
-    ## what you are doing...
-    _LT_COMPILER_PIC($1)
-    _LT_COMPILER_C_O($1)
-    _LT_COMPILER_FILE_LOCKS($1)
-    _LT_LINKER_SHLIBS($1)
-    _LT_SYS_DYNAMIC_LINKER($1)
-    _LT_LINKER_HARDCODE_LIBPATH($1)
-
-    _LT_CONFIG($1)
-  fi # test -n "$compiler"
-
-  GCC=$lt_save_GCC
-  CC="$lt_save_CC"
-  CFLAGS="$lt_save_CFLAGS"
-fi # test "$_lt_disable_F77" != yes
-
-AC_LANG_POP
-])# _LT_LANG_F77_CONFIG
-
-
-# _LT_LANG_FC_CONFIG([TAG])
-# -------------------------
-# Ensure that the configuration variables for a Fortran compiler are
-# suitably defined.  These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
-m4_defun([_LT_LANG_FC_CONFIG],
-[AC_LANG_PUSH(Fortran)
-
-if test -z "$FC" || test "X$FC" = "Xno"; then
-  _lt_disable_FC=yes
-fi
-
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-_LT_TAGVAR(allow_undefined_flag, $1)=
-_LT_TAGVAR(always_export_symbols, $1)=no
-_LT_TAGVAR(archive_expsym_cmds, $1)=
-_LT_TAGVAR(export_dynamic_flag_spec, $1)=
-_LT_TAGVAR(hardcode_direct, $1)=no
-_LT_TAGVAR(hardcode_direct_absolute, $1)=no
-_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
-_LT_TAGVAR(hardcode_libdir_separator, $1)=
-_LT_TAGVAR(hardcode_minus_L, $1)=no
-_LT_TAGVAR(hardcode_automatic, $1)=no
-_LT_TAGVAR(inherit_rpath, $1)=no
-_LT_TAGVAR(module_cmds, $1)=
-_LT_TAGVAR(module_expsym_cmds, $1)=
-_LT_TAGVAR(link_all_deplibs, $1)=unknown
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-_LT_TAGVAR(no_undefined_flag, $1)=
-_LT_TAGVAR(whole_archive_flag_spec, $1)=
-_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
-
-# Source file extension for fc test sources.
-ac_ext=${ac_fc_srcext-f}
-
-# Object file extension for compiled fc test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# No sense in running all these tests if we already determined that
-# the FC compiler isn't working.  Some variables (like enable_shared)
-# are currently assumed to apply to all compilers on this platform,
-# and will be corrupted by setting them based on a non-working compiler.
-if test "$_lt_disable_FC" != yes; then
-  # Code to be used in simple compile tests
-  lt_simple_compile_test_code="\
-      subroutine t
-      return
-      end
-"
-
-  # Code to be used in simple link tests
-  lt_simple_link_test_code="\
-      program t
-      end
-"
-
-  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
-  _LT_TAG_COMPILER
-
-  # save warnings/boilerplate of simple test code
-  _LT_COMPILER_BOILERPLATE
-  _LT_LINKER_BOILERPLATE
-
-  # Allow CC to be a program name with arguments.
-  lt_save_CC="$CC"
-  lt_save_GCC=$GCC
-  lt_save_CFLAGS=$CFLAGS
-  CC=${FC-"f95"}
-  CFLAGS=$FCFLAGS
-  compiler=$CC
-  GCC=$ac_cv_fc_compiler_gnu
-
-  _LT_TAGVAR(compiler, $1)=$CC
-  _LT_CC_BASENAME([$compiler])
-
-  if test -n "$compiler"; then
-    AC_MSG_CHECKING([if libtool supports shared libraries])
-    AC_MSG_RESULT([$can_build_shared])
-
-    AC_MSG_CHECKING([whether to build shared libraries])
-    test "$can_build_shared" = "no" && enable_shared=no
-
-    # On AIX, shared libraries and static libraries use the same namespace, and
-    # are all built from PIC.
-    case $host_os in
-      aix3*)
-        test "$enable_shared" = yes && enable_static=no
-        if test -n "$RANLIB"; then
-          archive_cmds="$archive_cmds~\$RANLIB \$lib"
-          postinstall_cmds='$RANLIB $lib'
-        fi
-        ;;
-      aix[[4-9]]*)
-       if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
-         test "$enable_shared" = yes && enable_static=no
-       fi
-        ;;
-    esac
-    AC_MSG_RESULT([$enable_shared])
-
-    AC_MSG_CHECKING([whether to build static libraries])
-    # Make sure either enable_shared or enable_static is yes.
-    test "$enable_shared" = yes || enable_static=yes
-    AC_MSG_RESULT([$enable_static])
-
-    _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
-    _LT_TAGVAR(LD, $1)="$LD"
-
-    ## CAVEAT EMPTOR:
-    ## There is no encapsulation within the following macros, do not change
-    ## the running order or otherwise move them around unless you know exactly
-    ## what you are doing...
-    _LT_SYS_HIDDEN_LIBDEPS($1)
-    _LT_COMPILER_PIC($1)
-    _LT_COMPILER_C_O($1)
-    _LT_COMPILER_FILE_LOCKS($1)
-    _LT_LINKER_SHLIBS($1)
-    _LT_SYS_DYNAMIC_LINKER($1)
-    _LT_LINKER_HARDCODE_LIBPATH($1)
-
-    _LT_CONFIG($1)
-  fi # test -n "$compiler"
-
-  GCC=$lt_save_GCC
-  CC=$lt_save_CC
-  CFLAGS=$lt_save_CFLAGS
-fi # test "$_lt_disable_FC" != yes
-
-AC_LANG_POP
-])# _LT_LANG_FC_CONFIG
-
-
-# _LT_LANG_GCJ_CONFIG([TAG])
-# --------------------------
-# Ensure that the configuration variables for the GNU Java Compiler compiler
-# are suitably defined.  These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
-m4_defun([_LT_LANG_GCJ_CONFIG],
-[AC_REQUIRE([LT_PROG_GCJ])dnl
-AC_LANG_SAVE
-
-# Source file extension for Java test sources.
-ac_ext=java
-
-# Object file extension for compiled Java test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code="class foo {}"
-
-# Code to be used in simple link tests
-lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
-
-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
-_LT_TAG_COMPILER
-
-# save warnings/boilerplate of simple test code
-_LT_COMPILER_BOILERPLATE
-_LT_LINKER_BOILERPLATE
-
-# Allow CC to be a program name with arguments.
-lt_save_CC=$CC
-lt_save_CFLAGS=$CFLAGS
-lt_save_GCC=$GCC
-GCC=yes
-CC=${GCJ-"gcj"}
-CFLAGS=$GCJFLAGS
-compiler=$CC
-_LT_TAGVAR(compiler, $1)=$CC
-_LT_TAGVAR(LD, $1)="$LD"
-_LT_CC_BASENAME([$compiler])
-
-# GCJ did not exist at the time GCC didn't implicitly link libc in.
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-
-if test -n "$compiler"; then
-  _LT_COMPILER_NO_RTTI($1)
-  _LT_COMPILER_PIC($1)
-  _LT_COMPILER_C_O($1)
-  _LT_COMPILER_FILE_LOCKS($1)
-  _LT_LINKER_SHLIBS($1)
-  _LT_LINKER_HARDCODE_LIBPATH($1)
-
-  _LT_CONFIG($1)
-fi
-
-AC_LANG_RESTORE
-
-GCC=$lt_save_GCC
-CC=$lt_save_CC
-CFLAGS=$lt_save_CFLAGS
-])# _LT_LANG_GCJ_CONFIG
-
-
-# _LT_LANG_RC_CONFIG([TAG])
-# -------------------------
-# Ensure that the configuration variables for the Windows resource compiler
-# are suitably defined.  These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
-m4_defun([_LT_LANG_RC_CONFIG],
-[AC_REQUIRE([LT_PROG_RC])dnl
-AC_LANG_SAVE
-
-# Source file extension for RC test sources.
-ac_ext=rc
-
-# Object file extension for compiled RC test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
-
-# Code to be used in simple link tests
-lt_simple_link_test_code="$lt_simple_compile_test_code"
-
-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
-_LT_TAG_COMPILER
-
-# save warnings/boilerplate of simple test code
-_LT_COMPILER_BOILERPLATE
-_LT_LINKER_BOILERPLATE
-
-# Allow CC to be a program name with arguments.
-lt_save_CC="$CC"
-lt_save_CFLAGS=$CFLAGS
-lt_save_GCC=$GCC
-GCC=
-CC=${RC-"windres"}
-CFLAGS=
-compiler=$CC
-_LT_TAGVAR(compiler, $1)=$CC
-_LT_CC_BASENAME([$compiler])
-_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
-
-if test -n "$compiler"; then
-  :
-  _LT_CONFIG($1)
-fi
-
-GCC=$lt_save_GCC
-AC_LANG_RESTORE
-CC=$lt_save_CC
-CFLAGS=$lt_save_CFLAGS
-])# _LT_LANG_RC_CONFIG
-
-
-# LT_PROG_GCJ
-# -----------
-AC_DEFUN([LT_PROG_GCJ],
-[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
-  [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
-    [AC_CHECK_TOOL(GCJ, gcj,)
-      test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
-      AC_SUBST(GCJFLAGS)])])[]dnl
-])
-
-# Old name:
-AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
-
-
-# LT_PROG_RC
-# ----------
-AC_DEFUN([LT_PROG_RC],
-[AC_CHECK_TOOL(RC, windres,)
-])
-
-# Old name:
-AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([LT_AC_PROG_RC], [])
-
-
-# _LT_DECL_EGREP
-# --------------
-# If we don't have a new enough Autoconf to choose the best grep
-# available, choose the one first in the user's PATH.
-m4_defun([_LT_DECL_EGREP],
-[AC_REQUIRE([AC_PROG_EGREP])dnl
-AC_REQUIRE([AC_PROG_FGREP])dnl
-test -z "$GREP" && GREP=grep
-_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
-_LT_DECL([], [EGREP], [1], [An ERE matcher])
-_LT_DECL([], [FGREP], [1], [A literal string matcher])
-dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
-AC_SUBST([GREP])
-])
-
-
-# _LT_DECL_OBJDUMP
-# --------------
-# If we don't have a new enough Autoconf to choose the best objdump
-# available, choose the one first in the user's PATH.
-m4_defun([_LT_DECL_OBJDUMP],
-[AC_CHECK_TOOL(OBJDUMP, objdump, false)
-test -z "$OBJDUMP" && OBJDUMP=objdump
-_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
-AC_SUBST([OBJDUMP])
-])
-
-# _LT_DECL_DLLTOOL
-# ----------------
-# Ensure DLLTOOL variable is set.
-m4_defun([_LT_DECL_DLLTOOL],
-[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
-test -z "$DLLTOOL" && DLLTOOL=dlltool
-_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
-AC_SUBST([DLLTOOL])
-])
-
-# _LT_DECL_SED
-# ------------
-# Check for a fully-functional sed program, that truncates
-# as few characters as possible.  Prefer GNU sed if found.
-m4_defun([_LT_DECL_SED],
-[AC_PROG_SED
-test -z "$SED" && SED=sed
-Xsed="$SED -e 1s/^X//"
-_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
-_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
-    [Sed that helps us avoid accidentally triggering echo(1) options like -n])
-])# _LT_DECL_SED
-
-m4_ifndef([AC_PROG_SED], [
-# NOTE: This macro has been submitted for inclusion into   #
-#  GNU Autoconf as AC_PROG_SED.  When it is available in   #
-#  a released version of Autoconf we should remove this    #
-#  macro and use it instead.                               #
-
-m4_defun([AC_PROG_SED],
-[AC_MSG_CHECKING([for a sed that does not truncate output])
-AC_CACHE_VAL(lt_cv_path_SED,
-[# Loop through the user's path and test for sed and gsed.
-# Then use that list of sed's as ones to test for truncation.
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for lt_ac_prog in sed gsed; do
-    for ac_exec_ext in '' $ac_executable_extensions; do
-      if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
-        lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
-      fi
-    done
-  done
-done
-IFS=$as_save_IFS
-lt_ac_max=0
-lt_ac_count=0
-# Add /usr/xpg4/bin/sed as it is typically found on Solaris
-# along with /bin/sed that truncates output.
-for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
-  test ! -f $lt_ac_sed && continue
-  cat /dev/null > conftest.in
-  lt_ac_count=0
-  echo $ECHO_N "0123456789$ECHO_C" >conftest.in
-  # Check for GNU sed and select it if it is found.
-  if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
-    lt_cv_path_SED=$lt_ac_sed
-    break
-  fi
-  while true; do
-    cat conftest.in conftest.in >conftest.tmp
-    mv conftest.tmp conftest.in
-    cp conftest.in conftest.nl
-    echo >>conftest.nl
-    $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
-    cmp -s conftest.out conftest.nl || break
-    # 10000 chars as input seems more than enough
-    test $lt_ac_count -gt 10 && break
-    lt_ac_count=`expr $lt_ac_count + 1`
-    if test $lt_ac_count -gt $lt_ac_max; then
-      lt_ac_max=$lt_ac_count
-      lt_cv_path_SED=$lt_ac_sed
-    fi
-  done
-done
-])
-SED=$lt_cv_path_SED
-AC_SUBST([SED])
-AC_MSG_RESULT([$SED])
-])#AC_PROG_SED
-])#m4_ifndef
-
-# Old name:
-AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([LT_AC_PROG_SED], [])
-
-
-# _LT_CHECK_SHELL_FEATURES
-# ------------------------
-# Find out whether the shell is Bourne or XSI compatible,
-# or has some other useful features.
-m4_defun([_LT_CHECK_SHELL_FEATURES],
-[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
-# Try some XSI features
-xsi_shell=no
-( _lt_dummy="a/b/c"
-  test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
-      = c,a/b,b/c, \
-    && eval 'test $(( 1 + 1 )) -eq 2 \
-    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
-  && xsi_shell=yes
-AC_MSG_RESULT([$xsi_shell])
-_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
-
-AC_MSG_CHECKING([whether the shell understands "+="])
-lt_shell_append=no
-( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
-    >/dev/null 2>&1 \
-  && lt_shell_append=yes
-AC_MSG_RESULT([$lt_shell_append])
-_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
-
-if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
-  lt_unset=unset
-else
-  lt_unset=false
-fi
-_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
-
-# test EBCDIC or ASCII
-case `echo X|tr X '\101'` in
- A) # ASCII based system
-    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
-  lt_SP2NL='tr \040 \012'
-  lt_NL2SP='tr \015\012 \040\040'
-  ;;
- *) # EBCDIC based system
-  lt_SP2NL='tr \100 \n'
-  lt_NL2SP='tr \r\n \100\100'
-  ;;
-esac
-_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
-_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
-])# _LT_CHECK_SHELL_FEATURES
-
-
-# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY)
-# ------------------------------------------------------
-# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and
-# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY.
-m4_defun([_LT_PROG_FUNCTION_REPLACE],
-[dnl {
-sed -e '/^$1 ()$/,/^} # $1 /c\
-$1 ()\
-{\
-m4_bpatsubsts([$2], [$], [\\], [^\([    ]\)], [\\\1])
-} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \
-  && mv -f "$cfgfile.tmp" "$cfgfile" \
-    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-])
-
-
-# _LT_PROG_REPLACE_SHELLFNS
-# -------------------------
-# Replace existing portable implementations of several shell functions with
-# equivalent extended shell implementations where those features are available..
-m4_defun([_LT_PROG_REPLACE_SHELLFNS],
-[if test x"$xsi_shell" = xyes; then
-  _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl
-    case ${1} in
-      */*) func_dirname_result="${1%/*}${2}" ;;
-      *  ) func_dirname_result="${3}" ;;
-    esac])
-
-  _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl
-    func_basename_result="${1##*/}"])
-
-  _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl
-    case ${1} in
-      */*) func_dirname_result="${1%/*}${2}" ;;
-      *  ) func_dirname_result="${3}" ;;
-    esac
-    func_basename_result="${1##*/}"])
-
-  _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl
-    # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
-    # positional parameters, so assign one to ordinary parameter first.
-    func_stripname_result=${3}
-    func_stripname_result=${func_stripname_result#"${1}"}
-    func_stripname_result=${func_stripname_result%"${2}"}])
-
-  _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl
-    func_split_long_opt_name=${1%%=*}
-    func_split_long_opt_arg=${1#*=}])
-
-  _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl
-    func_split_short_opt_arg=${1#??}
-    func_split_short_opt_name=${1%"$func_split_short_opt_arg"}])
-
-  _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl
-    case ${1} in
-      *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
-      *)    func_lo2o_result=${1} ;;
-    esac])
-
-  _LT_PROG_FUNCTION_REPLACE([func_xform], [    func_xform_result=${1%.*}.lo])
-
-  _LT_PROG_FUNCTION_REPLACE([func_arith], [    func_arith_result=$(( $[*] ))])
-
-  _LT_PROG_FUNCTION_REPLACE([func_len], [    func_len_result=${#1}])
-fi
-
-if test x"$lt_shell_append" = xyes; then
-  _LT_PROG_FUNCTION_REPLACE([func_append], [    eval "${1}+=\\${2}"])
-
-  _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl
-    func_quote_for_eval "${2}"
-dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \
-    eval "${1}+=\\\\ \\$func_quote_for_eval_result"])
-
-  # Save a `func_append' function call where possible by direct use of '+='
-  sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
-    && mv -f "$cfgfile.tmp" "$cfgfile" \
-      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-  test 0 -eq $? || _lt_function_replace_fail=:
-else
-  # Save a `func_append' function call even when '+=' is not available
-  sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
-    && mv -f "$cfgfile.tmp" "$cfgfile" \
-      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-  test 0 -eq $? || _lt_function_replace_fail=:
-fi
-
-if test x"$_lt_function_replace_fail" = x":"; then
-  AC_MSG_WARN([Unable to substitute extended shell functions in $ofile])
-fi
-])
-
-# _LT_PATH_CONVERSION_FUNCTIONS
-# -----------------------------
-# Determine which file name conversion functions should be used by
-# func_to_host_file (and, implicitly, by func_to_host_path).  These are needed
-# for certain cross-compile configurations and native mingw.
-m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-AC_MSG_CHECKING([how to convert $build file names to $host format])
-AC_CACHE_VAL(lt_cv_to_host_file_cmd,
-[case $host in
-  *-*-mingw* )
-    case $build in
-      *-*-mingw* ) # actually msys
-        lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
-        ;;
-      *-*-cygwin* )
-        lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
-        ;;
-      * ) # otherwise, assume *nix
-        lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
-        ;;
-    esac
-    ;;
-  *-*-cygwin* )
-    case $build in
-      *-*-mingw* ) # actually msys
-        lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
-        ;;
-      *-*-cygwin* )
-        lt_cv_to_host_file_cmd=func_convert_file_noop
-        ;;
-      * ) # otherwise, assume *nix
-        lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
-        ;;
-    esac
-    ;;
-  * ) # unhandled hosts (and "normal" native builds)
-    lt_cv_to_host_file_cmd=func_convert_file_noop
-    ;;
-esac
-])
-to_host_file_cmd=$lt_cv_to_host_file_cmd
-AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
-_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
-         [0], [convert $build file names to $host format])dnl
-
-AC_MSG_CHECKING([how to convert $build file names to toolchain format])
-AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
-[#assume ordinary cross tools, or native build.
-lt_cv_to_tool_file_cmd=func_convert_file_noop
-case $host in
-  *-*-mingw* )
-    case $build in
-      *-*-mingw* ) # actually msys
-        lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
-        ;;
-    esac
-    ;;
-esac
-])
-to_tool_file_cmd=$lt_cv_to_tool_file_cmd
-AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
-_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
-         [0], [convert $build files to toolchain format])dnl
-])# _LT_PATH_CONVERSION_FUNCTIONS
-
-# Helper functions for option handling.                    -*- Autoconf -*-
-#
-#   Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
-#   Inc.
-#   Written by Gary V. Vaughan, 2004
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# serial 7 ltoptions.m4
-
-# This is to help aclocal find these macros, as it can't see m4_define.
-AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+# generated automatically by aclocal 1.14.1 -*- Autoconf -*-
 
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
 
-# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
-# ------------------------------------------
-m4_define([_LT_MANGLE_OPTION],
-[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
-
-
-# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
-# ---------------------------------------
-# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
-# matching handler defined, dispatch to it.  Other OPTION-NAMEs are
-# saved as a flag.
-m4_define([_LT_SET_OPTION],
-[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
-m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
-        _LT_MANGLE_DEFUN([$1], [$2]),
-    [m4_warning([Unknown $1 option `$2'])])[]dnl
-])
-
-
-# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
-# ------------------------------------------------------------
-# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
-m4_define([_LT_IF_OPTION],
-[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
-
-
-# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
-# -------------------------------------------------------
-# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
-# are set.
-m4_define([_LT_UNLESS_OPTIONS],
-[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
-           [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
-                     [m4_define([$0_found])])])[]dnl
-m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
-])[]dnl
-])
-
-
-# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
-# ----------------------------------------
-# OPTION-LIST is a space-separated list of Libtool options associated
-# with MACRO-NAME.  If any OPTION has a matching handler declared with
-# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
-# the unknown option and exit.
-m4_defun([_LT_SET_OPTIONS],
-[# Set options
-m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
-    [_LT_SET_OPTION([$1], _LT_Option)])
-
-m4_if([$1],[LT_INIT],[
-  dnl
-  dnl Simply set some default values (i.e off) if boolean options were not
-  dnl specified:
-  _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
-  ])
-  _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
-  ])
-  dnl
-  dnl If no reference was made to various pairs of opposing options, then
-  dnl we run the default mode handler for the pair.  For example, if neither
-  dnl `shared' nor `disable-shared' was passed, we enable building of shared
-  dnl archives by default:
-  _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
-  _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
-  _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
-  _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
-                  [_LT_ENABLE_FAST_INSTALL])
-  ])
-])# _LT_SET_OPTIONS
-
-
-
-# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
-# -----------------------------------------
-m4_define([_LT_MANGLE_DEFUN],
-[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
-
-
-# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
-# -----------------------------------------------
-m4_define([LT_OPTION_DEFINE],
-[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
-])# LT_OPTION_DEFINE
-
-
-# dlopen
-# ------
-LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
-])
-
-AU_DEFUN([AC_LIBTOOL_DLOPEN],
-[_LT_SET_OPTION([LT_INIT], [dlopen])
-AC_DIAGNOSE([obsolete],
-[$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the `dlopen' option into LT_INIT's first parameter.])
-])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
-
-
-# win32-dll
-# ---------
-# Declare package support for building win32 dll's.
-LT_OPTION_DEFINE([LT_INIT], [win32-dll],
-[enable_win32_dll=yes
-
-case $host in
-*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
-  AC_CHECK_TOOL(AS, as, false)
-  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
-  AC_CHECK_TOOL(OBJDUMP, objdump, false)
-  ;;
-esac
-
-test -z "$AS" && AS=as
-_LT_DECL([], [AS],      [1], [Assembler program])dnl
-
-test -z "$DLLTOOL" && DLLTOOL=dlltool
-_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
-
-test -z "$OBJDUMP" && OBJDUMP=objdump
-_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
-])# win32-dll
-
-AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-_LT_SET_OPTION([LT_INIT], [win32-dll])
-AC_DIAGNOSE([obsolete],
-[$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the `win32-dll' option into LT_INIT's first parameter.])
-])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
-
-
-# _LT_ENABLE_SHARED([DEFAULT])
-# ----------------------------
-# implement the --enable-shared flag, and supports the `shared' and
-# `disable-shared' LT_INIT options.
-# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
-m4_define([_LT_ENABLE_SHARED],
-[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
-AC_ARG_ENABLE([shared],
-    [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
-       [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
-    [p=${PACKAGE-default}
-    case $enableval in
-    yes) enable_shared=yes ;;
-    no) enable_shared=no ;;
-    *)
-      enable_shared=no
-      # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
-      for pkg in $enableval; do
-       IFS="$lt_save_ifs"
-       if test "X$pkg" = "X$p"; then
-         enable_shared=yes
-       fi
-      done
-      IFS="$lt_save_ifs"
-      ;;
-    esac],
-    [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
-
-    _LT_DECL([build_libtool_libs], [enable_shared], [0],
-       [Whether or not to build shared libraries])
-])# _LT_ENABLE_SHARED
-
-LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
-LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
-
-# Old names:
-AC_DEFUN([AC_ENABLE_SHARED],
-[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
-])
-
-AC_DEFUN([AC_DISABLE_SHARED],
-[_LT_SET_OPTION([LT_INIT], [disable-shared])
-])
-
-AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
-AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AM_ENABLE_SHARED], [])
-dnl AC_DEFUN([AM_DISABLE_SHARED], [])
-
-
-
-# _LT_ENABLE_STATIC([DEFAULT])
-# ----------------------------
-# implement the --enable-static flag, and support the `static' and
-# `disable-static' LT_INIT options.
-# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
-m4_define([_LT_ENABLE_STATIC],
-[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
-AC_ARG_ENABLE([static],
-    [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
-       [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
-    [p=${PACKAGE-default}
-    case $enableval in
-    yes) enable_static=yes ;;
-    no) enable_static=no ;;
-    *)
-     enable_static=no
-      # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
-      for pkg in $enableval; do
-       IFS="$lt_save_ifs"
-       if test "X$pkg" = "X$p"; then
-         enable_static=yes
-       fi
-      done
-      IFS="$lt_save_ifs"
-      ;;
-    esac],
-    [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
-
-    _LT_DECL([build_old_libs], [enable_static], [0],
-       [Whether or not to build static libraries])
-])# _LT_ENABLE_STATIC
-
-LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
-LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
-
-# Old names:
-AC_DEFUN([AC_ENABLE_STATIC],
-[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
-])
-
-AC_DEFUN([AC_DISABLE_STATIC],
-[_LT_SET_OPTION([LT_INIT], [disable-static])
-])
-
-AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
-AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AM_ENABLE_STATIC], [])
-dnl AC_DEFUN([AM_DISABLE_STATIC], [])
-
-
-
-# _LT_ENABLE_FAST_INSTALL([DEFAULT])
-# ----------------------------------
-# implement the --enable-fast-install flag, and support the `fast-install'
-# and `disable-fast-install' LT_INIT options.
-# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
-m4_define([_LT_ENABLE_FAST_INSTALL],
-[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
-AC_ARG_ENABLE([fast-install],
-    [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
-    [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
-    [p=${PACKAGE-default}
-    case $enableval in
-    yes) enable_fast_install=yes ;;
-    no) enable_fast_install=no ;;
-    *)
-      enable_fast_install=no
-      # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
-      for pkg in $enableval; do
-       IFS="$lt_save_ifs"
-       if test "X$pkg" = "X$p"; then
-         enable_fast_install=yes
-       fi
-      done
-      IFS="$lt_save_ifs"
-      ;;
-    esac],
-    [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
-
-_LT_DECL([fast_install], [enable_fast_install], [0],
-        [Whether or not to optimize for fast installation])dnl
-])# _LT_ENABLE_FAST_INSTALL
-
-LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
-LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
-
-# Old names:
-AU_DEFUN([AC_ENABLE_FAST_INSTALL],
-[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
-AC_DIAGNOSE([obsolete],
-[$0: Remove this warning and the call to _LT_SET_OPTION when you put
-the `fast-install' option into LT_INIT's first parameter.])
-])
-
-AU_DEFUN([AC_DISABLE_FAST_INSTALL],
-[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
-AC_DIAGNOSE([obsolete],
-[$0: Remove this warning and the call to _LT_SET_OPTION when you put
-the `disable-fast-install' option into LT_INIT's first parameter.])
-])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
-dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
-
-
-# _LT_WITH_PIC([MODE])
-# --------------------
-# implement the --with-pic flag, and support the `pic-only' and `no-pic'
-# LT_INIT options.
-# MODE is either `yes' or `no'.  If omitted, it defaults to `both'.
-m4_define([_LT_WITH_PIC],
-[AC_ARG_WITH([pic],
-    [AS_HELP_STRING([--with-pic],
-       [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
-    [pic_mode="$withval"],
-    [pic_mode=default])
-
-test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
-
-_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
-])# _LT_WITH_PIC
-
-LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
-LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
-
-# Old name:
-AU_DEFUN([AC_LIBTOOL_PICMODE],
-[_LT_SET_OPTION([LT_INIT], [pic-only])
-AC_DIAGNOSE([obsolete],
-[$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the `pic-only' option into LT_INIT's first parameter.])
-])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
-
-
-m4_define([_LTDL_MODE], [])
-LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
-                [m4_define([_LTDL_MODE], [nonrecursive])])
-LT_OPTION_DEFINE([LTDL_INIT], [recursive],
-                [m4_define([_LTDL_MODE], [recursive])])
-LT_OPTION_DEFINE([LTDL_INIT], [subproject],
-                [m4_define([_LTDL_MODE], [subproject])])
-
-m4_define([_LTDL_TYPE], [])
-LT_OPTION_DEFINE([LTDL_INIT], [installable],
-                [m4_define([_LTDL_TYPE], [installable])])
-LT_OPTION_DEFINE([LTDL_INIT], [convenience],
-                [m4_define([_LTDL_TYPE], [convenience])])
-
-# ltsugar.m4 -- libtool m4 base layer.                         -*-Autoconf-*-
-#
-# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
-# Written by Gary V. Vaughan, 2004
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# serial 6 ltsugar.m4
-
-# This is to help aclocal find these macros, as it can't see m4_define.
-AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
-
-
-# lt_join(SEP, ARG1, [ARG2...])
-# -----------------------------
-# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
-# associated separator.
-# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
-# versions in m4sugar had bugs.
-m4_define([lt_join],
-[m4_if([$#], [1], [],
-       [$#], [2], [[$2]],
-       [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
-m4_define([_lt_join],
-[m4_if([$#$2], [2], [],
-       [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
-
-
-# lt_car(LIST)
-# lt_cdr(LIST)
-# ------------
-# Manipulate m4 lists.
-# These macros are necessary as long as will still need to support
-# Autoconf-2.59 which quotes differently.
-m4_define([lt_car], [[$1]])
-m4_define([lt_cdr],
-[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
-       [$#], 1, [],
-       [m4_dquote(m4_shift($@))])])
-m4_define([lt_unquote], $1)
-
-
-# lt_append(MACRO-NAME, STRING, [SEPARATOR])
-# ------------------------------------------
-# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
-# Note that neither SEPARATOR nor STRING are expanded; they are appended
-# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
-# No SEPARATOR is output if MACRO-NAME was previously undefined (different
-# than defined and empty).
-#
-# This macro is needed until we can rely on Autoconf 2.62, since earlier
-# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
-m4_define([lt_append],
-[m4_define([$1],
-          m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
-
-
-
-# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
-# ----------------------------------------------------------
-# Produce a SEP delimited list of all paired combinations of elements of
-# PREFIX-LIST with SUFFIX1 through SUFFIXn.  Each element of the list
-# has the form PREFIXmINFIXSUFFIXn.
-# Needed until we can rely on m4_combine added in Autoconf 2.62.
-m4_define([lt_combine],
-[m4_if(m4_eval([$# > 3]), [1],
-       [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
-[[m4_foreach([_Lt_prefix], [$2],
-            [m4_foreach([_Lt_suffix],
-               ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
-       [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
-
-
-# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
-# -----------------------------------------------------------------------
-# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
-# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
-m4_define([lt_if_append_uniq],
-[m4_ifdef([$1],
-         [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
-                [lt_append([$1], [$2], [$3])$4],
-                [$5])],
-         [lt_append([$1], [$2], [$3])$4])])
-
-
-# lt_dict_add(DICT, KEY, VALUE)
-# -----------------------------
-m4_define([lt_dict_add],
-[m4_define([$1($2)], [$3])])
-
-
-# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
-# --------------------------------------------
-m4_define([lt_dict_add_subkey],
-[m4_define([$1($2:$3)], [$4])])
-
-
-# lt_dict_fetch(DICT, KEY, [SUBKEY])
-# ----------------------------------
-m4_define([lt_dict_fetch],
-[m4_ifval([$3],
-       m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
-    m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
-
-
-# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
-# -----------------------------------------------------------------
-m4_define([lt_if_dict_fetch],
-[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
-       [$5],
-    [$6])])
-
-
-# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
-# --------------------------------------------------------------
-m4_define([lt_dict_filter],
-[m4_if([$5], [], [],
-  [lt_join(m4_quote(m4_default([$4], [[, ]])),
-           lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
-                     [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
-])
-
-# ltversion.m4 -- version numbers                      -*- Autoconf -*-
-#
-#   Copyright (C) 2004 Free Software Foundation, Inc.
-#   Written by Scott James Remnant, 2004
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# @configure_input@
-
-# serial 3293 ltversion.m4
-# This file is part of GNU Libtool
-
-m4_define([LT_PACKAGE_VERSION], [2.4])
-m4_define([LT_PACKAGE_REVISION], [1.3293])
-
-AC_DEFUN([LTVERSION_VERSION],
-[macro_version='2.4'
-macro_revision='1.3293'
-_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
-_LT_DECL(, macro_revision, 0)
-])
-
-# lt~obsolete.m4 -- aclocal satisfying obsolete definitions.    -*-Autoconf-*-
-#
-#   Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
-#   Written by Scott James Remnant, 2004.
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# serial 5 lt~obsolete.m4
-
-# These exist entirely to fool aclocal when bootstrapping libtool.
-#
-# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
-# which have later been changed to m4_define as they aren't part of the
-# exported API, or moved to Autoconf or Automake where they belong.
-#
-# The trouble is, aclocal is a bit thick.  It'll see the old AC_DEFUN
-# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
-# using a macro with the same name in our local m4/libtool.m4 it'll
-# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
-# and doesn't know about Autoconf macros at all.)
-#
-# So we provide this file, which has a silly filename so it's always
-# included after everything else.  This provides aclocal with the
-# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
-# because those macros already exist, or will be overwritten later.
-# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. 
-#
-# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
-# Yes, that means every name once taken will need to remain here until
-# we give up compatibility with versions before 1.7, at which point
-# we need to keep only those names which we still refer to.
-
-# This is to help aclocal find these macros, as it can't see m4_define.
-AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
 
-m4_ifndef([AC_LIBTOOL_LINKER_OPTION],  [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
-m4_ifndef([AC_PROG_EGREP],             [AC_DEFUN([AC_PROG_EGREP])])
-m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH],        [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
-m4_ifndef([_LT_AC_SHELL_INIT],         [AC_DEFUN([_LT_AC_SHELL_INIT])])
-m4_ifndef([_LT_AC_SYS_LIBPATH_AIX],    [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
-m4_ifndef([_LT_PROG_LTMAIN],           [AC_DEFUN([_LT_PROG_LTMAIN])])
-m4_ifndef([_LT_AC_TAGVAR],             [AC_DEFUN([_LT_AC_TAGVAR])])
-m4_ifndef([AC_LTDL_ENABLE_INSTALL],    [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
-m4_ifndef([AC_LTDL_PREOPEN],           [AC_DEFUN([AC_LTDL_PREOPEN])])
-m4_ifndef([_LT_AC_SYS_COMPILER],       [AC_DEFUN([_LT_AC_SYS_COMPILER])])
-m4_ifndef([_LT_AC_LOCK],               [AC_DEFUN([_LT_AC_LOCK])])
-m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE],        [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
-m4_ifndef([_LT_AC_TRY_DLOPEN_SELF],    [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
-m4_ifndef([AC_LIBTOOL_PROG_CC_C_O],    [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
-m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
-m4_ifndef([AC_LIBTOOL_OBJDIR],         [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
-m4_ifndef([AC_LTDL_OBJDIR],            [AC_DEFUN([AC_LTDL_OBJDIR])])
-m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
-m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP],  [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
-m4_ifndef([AC_PATH_MAGIC],             [AC_DEFUN([AC_PATH_MAGIC])])
-m4_ifndef([AC_PROG_LD_GNU],            [AC_DEFUN([AC_PROG_LD_GNU])])
-m4_ifndef([AC_PROG_LD_RELOAD_FLAG],    [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
-m4_ifndef([AC_DEPLIBS_CHECK_METHOD],   [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
-m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
-m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
-m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
-m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
-m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
-m4_ifndef([LT_AC_PROG_EGREP],          [AC_DEFUN([LT_AC_PROG_EGREP])])
-m4_ifndef([LT_AC_PROG_SED],            [AC_DEFUN([LT_AC_PROG_SED])])
-m4_ifndef([_LT_CC_BASENAME],           [AC_DEFUN([_LT_CC_BASENAME])])
-m4_ifndef([_LT_COMPILER_BOILERPLATE],  [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
-m4_ifndef([_LT_LINKER_BOILERPLATE],    [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
-m4_ifndef([_AC_PROG_LIBTOOL],          [AC_DEFUN([_AC_PROG_LIBTOOL])])
-m4_ifndef([AC_LIBTOOL_SETUP],          [AC_DEFUN([AC_LIBTOOL_SETUP])])
-m4_ifndef([_LT_AC_CHECK_DLFCN],                [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
-m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER],     [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
-m4_ifndef([_LT_AC_TAGCONFIG],          [AC_DEFUN([_LT_AC_TAGCONFIG])])
-m4_ifndef([AC_DISABLE_FAST_INSTALL],   [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
-m4_ifndef([_LT_AC_LANG_CXX],           [AC_DEFUN([_LT_AC_LANG_CXX])])
-m4_ifndef([_LT_AC_LANG_F77],           [AC_DEFUN([_LT_AC_LANG_F77])])
-m4_ifndef([_LT_AC_LANG_GCJ],           [AC_DEFUN([_LT_AC_LANG_GCJ])])
-m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG],  [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
-m4_ifndef([_LT_AC_LANG_C_CONFIG],      [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG],        [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
-m4_ifndef([_LT_AC_LANG_CXX_CONFIG],    [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG],        [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
-m4_ifndef([_LT_AC_LANG_F77_CONFIG],    [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG],        [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
-m4_ifndef([_LT_AC_LANG_GCJ_CONFIG],    [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
-m4_ifndef([_LT_AC_LANG_RC_CONFIG],     [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
-m4_ifndef([AC_LIBTOOL_CONFIG],         [AC_DEFUN([AC_LIBTOOL_CONFIG])])
-m4_ifndef([_LT_AC_FILE_LTDLL_C],       [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
-m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS],        [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
-m4_ifndef([_LT_AC_PROG_CXXCPP],                [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
-m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS],        [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
-m4_ifndef([_LT_PROG_ECHO_BACKSLASH],   [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
-m4_ifndef([_LT_PROG_F77],              [AC_DEFUN([_LT_PROG_F77])])
-m4_ifndef([_LT_PROG_FC],               [AC_DEFUN([_LT_PROG_FC])])
-m4_ifndef([_LT_PROG_CXX],              [AC_DEFUN([_LT_PROG_CXX])])
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
 
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
 # AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
 
-# Copyright (C) 2001, 2003, 2005  Free Software Foundation, Inc.
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
 # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
-# $ac_aux_dir to `$srcdir/foo'.  In other projects, it is set to
-# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
+# $ac_aux_dir to '$srcdir/foo'.  In other projects, it is set to
+# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
 #
 # Of course, Automake must honor this variable whenever it calls a
 # tool from the auxiliary directory.  The problem is that $srcdir (and
@@ -8446,7 +41,7 @@ m4_ifndef([_LT_PROG_CXX],           [AC_DEFUN([_LT_PROG_CXX])])
 #
 # The reason of the latter failure is that $top_srcdir and $ac_aux_dir
 # are both prefixed by $srcdir.  In an in-source build this is usually
-# harmless because $srcdir is `.', but things will broke when you
+# harmless because $srcdir is '.', but things will broke when you
 # start a VPATH build or use an absolute $srcdir.
 #
 # So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
@@ -8464,23 +59,19 @@ m4_ifndef([_LT_PROG_CXX],         [AC_DEFUN([_LT_PROG_CXX])])
 # configured tree to be moved without reconfiguration.
 
 AC_DEFUN([AM_AUX_DIR_EXPAND],
-[dnl Rely on autoconf to set up CDPATH properly.
-AC_PREREQ([2.50])dnl
-# expand $ac_aux_dir to an absolute path
-am_aux_dir=`cd $ac_aux_dir && pwd`
+[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
 ])
 
 # Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
 
-# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008
-# Free Software Foundation, Inc.
+# Copyright (C) 1997-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 6
-
 # AM_MISSING_PROG(NAME, PROGRAM)
 # ------------------------------
 AC_DEFUN([AM_MISSING_PROG],
@@ -8488,11 +79,10 @@ AC_DEFUN([AM_MISSING_PROG],
 $1=${$1-"${am_missing_run}$2"}
 AC_SUBST($1)])
 
-
 # AM_MISSING_HAS_RUN
 # ------------------
-# Define MISSING if not defined so far and test if it supports --run.
-# If it does, set am_missing_run to use it, otherwise, to nothing.
+# Define MISSING if not defined so far and test if it is modern enough.
+# If it is, set am_missing_run to use it, otherwise, to nothing.
 AC_DEFUN([AM_MISSING_HAS_RUN],
 [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
 AC_REQUIRE_AUX_FILE([missing])dnl
@@ -8505,11 +95,11 @@ if test x"${MISSING+set}" != xset; then
   esac
 fi
 # Use eval to expand $SHELL
-if eval "$MISSING --run true"; then
-  am_missing_run="$MISSING --run "
+if eval "$MISSING --is-lightweight"; then
+  am_missing_run="$MISSING "
 else
   am_missing_run=
-  AC_MSG_WARN([`missing' script is too old or missing])
+  AC_MSG_WARN(['missing' script is too old or missing])
 fi
 ])
 
index ebcc6ba..9d6a080 100755 (executable)
--- a/configure
+++ b/configure
@@ -2422,10 +2422,7 @@ RADIUSD_MAJOR_VERSION=`cat VERSION | cut -f1 -d.`
 RADIUSD_MINOR_VERSION=`cat VERSION | cut -f2 -d.`
 RADIUSD_INCRM_VERSION=`cat VERSION | cut -f3 -d. | sed 's/[\.-].*$//'`
 
-RADIUSD_VERSION=`echo | awk -v major="$RADIUSD_MAJOR_VERSION" \
--v minor="$RADIUSD_MINOR_VERSION" \
--v incrm="$RADIUSD_INCRM_VERSION" \
-'{ printf "%02i%02i%02i", major, minor, incrm }'`
+RADIUSD_VERSION=`printf "%02i%02i%02i" $RADIUSD_MAJOR_VERSION $RADIUSD_MINOR_VERSION $RADIUSD_INCRM_VERSION`
 
 RADIUSD_VERSION_STRING=`cat VERSION`
 
@@ -5651,8 +5648,8 @@ fi
 
 
 missing_dir=`cd $ac_aux_dir && pwd`
-# expand $ac_aux_dir to an absolute path
-am_aux_dir=`cd $ac_aux_dir && pwd`
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
 
 if test x"${MISSING+set}" != xset; then
   case $am_aux_dir in
@@ -5663,12 +5660,12 @@ if test x"${MISSING+set}" != xset; then
   esac
 fi
 # Use eval to expand $SHELL
-if eval "$MISSING --run true"; then
-  am_missing_run="$MISSING --run "
+if eval "$MISSING --is-lightweight"; then
+  am_missing_run="$MISSING "
 else
   am_missing_run=
-  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5
-$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
 fi
 
 
@@ -7958,50 +7955,50 @@ fi
 
 
 for ac_header in \
-  dlfcn.h \
-  unistd.h \
+  arpa/inet.h \
   crypt.h \
+  dlfcn.h \
   errno.h \
-  resource.h \
-  sys/resource.h \
+  fcntl.h \
+  features.h \
+  fnmatch.h \
   getopt.h \
+  glob.h \
+  grp.h \
+  inttypes.h \
+  limits.h \
   malloc.h \
-  utmp.h \
-  utmpx.h \
+  netdb.h \
+  netinet/in.h \
+  prot.h \
+  pwd.h \
+  resource.h \
+  semaphore.h \
+  sia.h \
+  siad.h \
   signal.h \
-  sys/select.h \
-  syslog.h \
-  inttypes.h \
-  stdint.h \
   stdbool.h \
+  stddef.h \
+  stdint.h \
   stdio.h \
-  netdb.h \
-  semaphore.h \
-  arpa/inet.h \
-  netinet/in.h \
-  sys/types.h \
-  sys/socket.h \
-  winsock.h \
-  utime.h \
-  sys/time.h \
-  sys/wait.h \
-  sys/security.h \
-  fcntl.h \
+  sys/event.h \
   sys/fcntl.h \
   sys/prctl.h \
   sys/ptrace.h \
+  sys/resource.h \
+  sys/security.h \
+  sys/select.h \
+  sys/socket.h \
+  sys/time.h \
+  sys/types.h \
   sys/un.h \
-  glob.h \
-  prot.h \
-  pwd.h \
-  grp.h \
-  stddef.h \
-  fnmatch.h \
-  sia.h \
-  siad.h \
-  features.h \
-  limits.h \
-  sys/event.h
+  sys/wait.h \
+  syslog.h \
+  unistd.h \
+  utime.h \
+  utmp.h \
+  utmpx.h \
+  winsock.h
 
 do :
   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
@@ -8734,10 +8731,11 @@ rm -f conftest*
                 { $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 :
-  { { $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
-See \`config.log' for more details" "$LINENO" 5; }
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: cross-compiling (assuming yes)" >&5
+$as_echo "cross-compiling (assuming yes)" >&6; }
+
+
 else
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
@@ -8776,7 +8774,6 @@ $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; }
 
-
 fi
 rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
   conftest.$ac_objext conftest.beam conftest.$ac_ext
@@ -8790,6 +8787,17 @@ fi
 
 
   export OPENSSL_LIBS OPENSSL_LDFLAGS OPENSSL_CPPFLAGS
+  for ac_func in SSL_get_client_random
+do :
+  ac_fn_c_check_func "$LINENO" "SSL_get_client_random" "ac_cv_func_SSL_get_client_random"
+if test "x$ac_cv_func_SSL_get_client_random" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SSL_GET_CLIENT_RANDOM 1
+_ACEOF
+ SSL_get_server_random
+fi
+done
+
 fi
 
 if test "x$PCAP_LIBS" = x; then
@@ -9926,45 +9934,50 @@ rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
 
 for ac_func in \
-  getopt_long \
-  fcntl \
-  strsignal \
-  sigaction \
-  sigprocmask \
-  pthread_sigmask \
-  snprintf \
-  vsnprintf \
-  setsid \
-  strncasecmp \
-  strcasecmp \
-  localtime_r \
+  bindat \
+  clock_gettime \
+  closefrom \
   ctime_r \
+  dladdr \
+  fcntl \
+  fopencookie \
+  funopen \
+  getaddrinfo \
+  getnameinfo \
+  getopt_long \
+  getpeereid \
+  getresuid \
+  gettimeofday \
+  getusershell \
   gmtime_r \
-  strsep \
+  if_indextoname \
   inet_aton \
-  inet_pton \
   inet_ntop \
+  inet_pton \
+  initgroups \
+  kqueue \
+  localtime_r \
   mallopt \
+  mkdirat \
+  openat \
+  pthread_sigmask \
   setlinebuf \
-  setvbuf \
-  getusershell \
-  initgroups \
-  getaddrinfo \
-  getnameinfo \
-  closefrom \
-  gettimeofday \
-  getpeereid \
-  setuid \
   setresuid \
-  getresuid \
+  setsid \
+  setuid \
+  setvbuf \
+  sigaction \
+  sigprocmask \
+  snprintf \
+  strcasecmp \
   strlcat \
   strlcpy \
-  kqueue \
-  openat \
-  mkdirat \
+  strncasecmp \
+  strsep \
+  strsignal \
   unlinkat \
-  bindat \
-  dladdr
+  vdprintf \
+  vsnprintf
 
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
@@ -10430,7 +10443,7 @@ fi
 $as_echo "$ax_cv_cc_weverything_flag" >&6; }
 
   if test "x$ax_cv_cc_weverything_flag" = "xyes"; then
-    devflags="$devflags -W -Weverything -Wformat=2 -Wno-missing-field-initializers -Wno-date-time -Wno-padded -Wno-gnu-zero-variadic-macro-arguments -Wno-shorten-64-to-32 -Wno-sign-conversion -Wno-conversion -Wno-switch-enum -Wno-gnu-statement-expression -Wno-extended-offsetof -Wno-cast-align -Wno-documentation-unknown-command -Wno-covered-switch-default -Wno-packed -Wno-reserved-id-macro -DWITH_VERIFY_PTR=1"
+    devflags="$devflags -W -Weverything -Wformat=2 -Wno-missing-field-initializers -Wno-date-time -Wno-padded -Wno-gnu-zero-variadic-macro-arguments -Wno-shorten-64-to-32 -Wno-sign-conversion -Wno-conversion -Wno-switch-enum -Wno-gnu-statement-expression -Wno-extended-offsetof -Wno-cast-align -Wno-documentation-unknown-command -Wno-covered-switch-default -Wno-packed -DWITH_VERIFY_PTR=1"
   else
     if test "x$GCC" = "xyes"; then
       devflags="$devflags -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -W -Wredundant-decls -Wundef -Wformat-y2k -Wno-format-extra-args -Wno-format-zero-length -Wno-cast-align -Wformat-nonliteral -Wformat-security -Wformat=2 -DWITH_VERIFY_PTR=1"
index d1921f1..90c35bd 100644 (file)
@@ -37,10 +37,7 @@ RADIUSD_MAJOR_VERSION=`cat VERSION | cut -f1 -d.`
 RADIUSD_MINOR_VERSION=`cat VERSION | cut -f2 -d.`
 RADIUSD_INCRM_VERSION=`cat VERSION | cut -f3 -d. | sed 's/[[\.-]].*$//'`
 
-RADIUSD_VERSION=`echo | awk -v major="$RADIUSD_MAJOR_VERSION" \
--v minor="$RADIUSD_MINOR_VERSION" \
--v incrm="$RADIUSD_INCRM_VERSION" \
-'{ printf "%02i%02i%02i", major, minor, incrm }'`
+RADIUSD_VERSION=`printf "%02i%02i%02i" $RADIUSD_MAJOR_VERSION $RADIUSD_MINOR_VERSION $RADIUSD_INCRM_VERSION`
 
 dnl #
 dnl #  Still useful for custom builds
@@ -995,50 +992,50 @@ AC_HEADER_TIME
 AC_HEADER_SYS_WAIT
 
 AC_CHECK_HEADERS( \
-  dlfcn.h \
-  unistd.h \
+  arpa/inet.h \
   crypt.h \
+  dlfcn.h \
   errno.h \
-  resource.h \
-  sys/resource.h \
+  fcntl.h \
+  features.h \
+  fnmatch.h \
   getopt.h \
+  glob.h \
+  grp.h \
+  inttypes.h \
+  limits.h \
   malloc.h \
-  utmp.h \
-  utmpx.h \
+  netdb.h \
+  netinet/in.h \
+  prot.h \
+  pwd.h \
+  resource.h \
+  semaphore.h \
+  sia.h \
+  siad.h \
   signal.h \
-  sys/select.h \
-  syslog.h \
-  inttypes.h \
-  stdint.h \
   stdbool.h \
+  stddef.h \
+  stdint.h \
   stdio.h \
-  netdb.h \
-  semaphore.h \
-  arpa/inet.h \
-  netinet/in.h \
-  sys/types.h \
-  sys/socket.h \
-  winsock.h \
-  utime.h \
-  sys/time.h \
-  sys/wait.h \
-  sys/security.h \
-  fcntl.h \
+  sys/event.h \
   sys/fcntl.h \
   sys/prctl.h \
   sys/ptrace.h \
+  sys/resource.h \
+  sys/security.h \
+  sys/select.h \
+  sys/socket.h \
+  sys/time.h \
+  sys/types.h \
   sys/un.h \
-  glob.h \
-  prot.h \
-  pwd.h \
-  grp.h \
-  stddef.h \
-  fnmatch.h \
-  sia.h \
-  siad.h \
-  features.h \
-  limits.h \
-  sys/event.h
+  sys/wait.h \
+  syslog.h \
+  unistd.h \
+  utime.h \
+  utmp.h \
+  utmpx.h \
+  winsock.h
 )
 
 dnl #
@@ -1172,6 +1169,9 @@ if test "x$WITH_OPENSSL" = xyes; then
       [
         AC_MSG_RESULT(no)
         AC_MSG_FAILURE([OpenSSL library version does not match header version])
+      ],
+      [
+        AC_MSG_RESULT([cross-compiling (assuming yes)])
       ]
     )
     CPPFLAGS="$old_CPPFLAGS"
@@ -1182,6 +1182,7 @@ if test "x$WITH_OPENSSL" = xyes; then
   AC_SUBST(OPENSSL_LDFLAGS)
   AC_SUBST(OPENSSL_CPPFLAGS)
   export OPENSSL_LIBS OPENSSL_LDFLAGS OPENSSL_CPPFLAGS
+  AC_CHECK_FUNCS(SSL_get_client_random,SSL_get_server_random)
 fi
 
 dnl #
@@ -1429,45 +1430,50 @@ dnl #  5. Checks for structures and functions
 dnl #
 dnl #############################################################
 AC_CHECK_FUNCS( \
-  getopt_long \
-  fcntl \
-  strsignal \
-  sigaction \
-  sigprocmask \
-  pthread_sigmask \
-  snprintf \
-  vsnprintf \
-  setsid \
-  strncasecmp \
-  strcasecmp \
-  localtime_r \
+  bindat \
+  clock_gettime \
+  closefrom \
   ctime_r \
+  dladdr \
+  fcntl \
+  fopencookie \
+  funopen \
+  getaddrinfo \
+  getnameinfo \
+  getopt_long \
+  getpeereid \
+  getresuid \
+  gettimeofday \
+  getusershell \
   gmtime_r \
-  strsep \
+  if_indextoname \
   inet_aton \
-  inet_pton \
   inet_ntop \
+  inet_pton \
+  initgroups \
+  kqueue \
+  localtime_r \
   mallopt \
+  mkdirat \
+  openat \
+  pthread_sigmask \
   setlinebuf \
-  setvbuf \
-  getusershell \
-  initgroups \
-  getaddrinfo \
-  getnameinfo \
-  closefrom \
-  gettimeofday \
-  getpeereid \
-  setuid \
   setresuid \
-  getresuid \
+  setsid \
+  setuid \
+  setvbuf \
+  sigaction \
+  sigprocmask \
+  snprintf \
+  strcasecmp \
   strlcat \
   strlcpy \
-  kqueue \
-  openat \
-  mkdirat \
+  strncasecmp \
+  strsep \
+  strsignal \
   unlinkat \
-  bindat \
-  dladdr
+  vdprintf \
+  vsnprintf
 )
 
 AC_TYPE_SIGNAL
@@ -1584,7 +1590,7 @@ if test "x$developer" = "xyes"; then
   dnl #
   AX_CC_WEVERYTHING_FLAG
   if test "x$ax_cv_cc_weverything_flag" = "xyes"; then
-    devflags="$devflags -W -Weverything -Wformat=2 -Wno-missing-field-initializers -Wno-date-time -Wno-padded -Wno-gnu-zero-variadic-macro-arguments -Wno-shorten-64-to-32 -Wno-sign-conversion -Wno-conversion -Wno-switch-enum -Wno-gnu-statement-expression -Wno-extended-offsetof -Wno-cast-align -Wno-documentation-unknown-command -Wno-covered-switch-default -Wno-packed -Wno-reserved-id-macro -DWITH_VERIFY_PTR=1"
+    devflags="$devflags -W -Weverything -Wformat=2 -Wno-missing-field-initializers -Wno-date-time -Wno-padded -Wno-gnu-zero-variadic-macro-arguments -Wno-shorten-64-to-32 -Wno-sign-conversion -Wno-conversion -Wno-switch-enum -Wno-gnu-statement-expression -Wno-extended-offsetof -Wno-cast-align -Wno-documentation-unknown-command -Wno-covered-switch-default -Wno-packed -DWITH_VERIFY_PTR=1"
   else
     if test "x$GCC" = "xyes"; then
       devflags="$devflags -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -W -Wredundant-decls -Wundef -Wformat-y2k -Wno-format-extra-args -Wno-format-zero-length -Wno-cast-align -Wformat-nonliteral -Wformat-security -Wformat=2 -DWITH_VERIFY_PTR=1"
index 19b0c79..0ba5653 100644 (file)
@@ -1,3 +1,15 @@
+freeradius (3.0.12+git) unstable; urgency=medium
+
+  * New upstream version.
+
+ -- Alan DeKok <aland@freeradius.org>  Mon, 25 Jan 2016 14:00:00 -0400
+
+freeradius (3.0.11+git) unstable; urgency=medium
+
+  * New upstream version.
+
+ -- Alan DeKok <aland@freeradius.org>  Mon, 05 Oct 2015 15:00:00 -0400
+
 freeradius (3.0.10+git) unstable; urgency=medium
 
   * New upstream version.
index 34e8e5e..c911c3c 100644 (file)
@@ -9,7 +9,7 @@ Build-Depends: debhelper (>= 9),
  libiodbc2-dev,
  libjson0 | libjson-c2,
  libjson0-dev | libjson-c-dev,
- libkrb5-dev,
+ libkrb5-dev | heimdal-dev,
  libldap2-dev,
  libpam0g-dev,
  libpcap-dev,
@@ -26,7 +26,8 @@ Build-Depends: debhelper (>= 9),
  libykclient-dev,
  libmemcached-dev,
  libhiredis-dev,
- python-dev
+ python-dev,
+ samba-dev | samba4-dev
 Section: net
 Priority: optional
 Maintainer: Josip Rodin <joy-packages@debian.org>
@@ -61,7 +62,7 @@ Description: FreeRADIUS common files
 
 Package: freeradius-config
 Architecture: any
-Depends: freeradius-common (>= 3), ${misc:Depends}, openssl
+Depends: freeradius-common (>= 3), ${misc:Depends}, openssl, make
 Breaks: freeradius-config
 Description: FreeRADIUS default config files
  This package should be used as a base for a site local packages
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index 17d93cd..ac4cb68 100644 (file)
@@ -1,6 +1,15 @@
-# Options for the FreeRADIUS deamon.
+# Options passed to the FreeRADIUS deamon.
+#
+FREERADIUS_OPTIONS=""
+
+
+# If FreeRADIUS is being used on a SysVinit system
+# and FREERADIUS_OPTIONS has not been set and the
+# following location exists, then it will be used
+# for the config directory rather than the default.
+#
+# This option has no effect when systemd is in
+# use, or if FREERADIUS_OPTIONS is set above.
+#
 FREERADIUS_CONF_LOCAL="/usr/local/etc/freeradius"
 
-if [ -d "$FREERADIUS_CONF_LOCAL" ]; then
-       FREERADIUS_OPTIONS="-d $FREERADIUS_CONF_LOCAL"
-fi
index a281e62..046aee8 100755 (executable)
@@ -42,6 +42,10 @@ if [ ! -d /var/run/freeradius ]; then
     chown freerad:freerad /var/run/freeradius
 fi
 
+if [ -d "$FREERADIUS_CONF_LOCAL" -a -z "$FREERADIUS_OPTIONS" ]; then
+  FREERADIUS_OPTIONS="-d $FREERADIUS_CONF_LOCAL"
+fi
+
 export PATH="${PATH:+$PATH:}/usr/sbin:/sbin"
 
 ret=0
index 3c007cd..02f95c0 100644 (file)
@@ -1,4 +1,4 @@
-# You can use this to rotate the /var/log/radius/* files, simply copy
+# You can use this to rotate the /var/log/freeradius/* files, simply copy
 # it to /etc/logrotate.d/radiusd
 
 #
@@ -14,28 +14,28 @@ notifempty
 #
 #  The main server log
 #
-/var/log/radius/radius.log {
+/var/log/freeradius/radius.log {
        copytruncate
 }
 
 #
 #  Session monitoring utilities
 #
-/var/log/radius/checkrad.log /var/log/radius/radwatch.log {
+/var/log/freeradius/checkrad.log /var/log/freeradius/radwatch.log {
        nocreate
 }
 
 #
 #  Session database modules
 #
-/var/log/radius/radutmp /var/log/radius/radwtmp {
+/var/log/freeradius/radutmp /var/log/freeradius/radwtmp {
        nocreate
 }
 
 #
 #  SQL log files
 #
-/var/log/radius/sqllog.sql {
+/var/log/freeradius/sqllog.sql {
        nocreate
 }
 
@@ -46,6 +46,6 @@ notifempty
 # (or similar) in radiusd.conf, without rotation.  If you go with the
 # second technique, you will need another cron job that removes old
 # detail files.  You do not need to comment out the below for method #2.
-/var/log/radius/radacct/*/detail {
+/var/log/freeradius/radacct/*/detail {
        nocreate
 }
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/debian/freeradius.service b/debian/freeradius.service
new file mode 100644 (file)
index 0000000..43eb3d0
--- /dev/null
@@ -0,0 +1,16 @@
+[Unit]
+Description=FreeRADIUS multi-protocol policy server
+After=syslog.target network.target
+Documentation=man:radiusd(8) man:radiusd.conf(5) http://wiki.freeradius.org/ http://networkradius.com/doc/
+
+[Service]
+Type=forking
+PIDFile=/run/freeradius/freeradius.pid
+EnvironmentFile=-/etc/default/freeradius
+ExecStartPre=/usr/sbin/freeradius $FREERADIUS_OPTIONS -Cxm -lstdout
+ExecStart=/usr/sbin/freeradius $FREERADIUS_OPTIONS
+Restart=on-failure
+RestartSec=5
+
+[Install]
+WantedBy=multi-user.target
diff --git a/debian/patches/logrotate-path.diff b/debian/patches/logrotate-path.diff
deleted file mode 100644 (file)
index 6d1871f..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-diff --git a/scripts/logrotate/freeradius b/scripts/logrotate/freeradius
-index cbeeb5f..bfb8220 100644
---- a/scripts/logrotate/freeradius
-+++ b/scripts/logrotate/freeradius
-@@ -1,7 +1,7 @@
- #
- #  Sample logrotate file for FreeRADIUS
- #
--#  You can use this to rotate the /var/log/radius/* files, simply copy it to /etc/logrotate.d/radiusd
-+#  You can use this to rotate the /var/log/freeradius/* files, simply copy it to /etc/logrotate.d/radiusd
- #
- #
-@@ -17,28 +17,28 @@ notifempty
- #
- #  The main server log
- #
--/var/log/radius/radius.log {
-+/var/log/freeradius/radius.log {
-       copytruncate
- }
- #
- #  Session monitoring utilities
- #
--/var/log/radius/checkrad.log /var/log/radius/radwatch.log {
-+/var/log/freeradius/checkrad.log /var/log/freeradius/radwatch.log {
-       nocreate
- }
- #
- #  Session database modules
- #
--/var/log/radius/radutmp /var/log/radius/radwtmp {
-+/var/log/freeradius/radutmp /var/log/freeradius/radwtmp {
-       nocreate
- }
- #
- #  SQL log files
- #
--/var/log/radius/sqllog.sql {
-+/var/log/freeradius/sqllog.sql {
-       nocreate
- }
-@@ -49,6 +49,6 @@ notifempty
- # (or similar) in radiusd.conf, without rotation.  If you go with the
- # second technique, you will need another cron job that removes old
- # detail files.  You do not need to comment out the below for method #2.
--/var/log/radius/radacct/*/detail {
-+/var/log/freeradius/radacct/*/detail {
-       nocreate
- }
index a0c089d..b3625f8 100644 (file)
@@ -1,8 +1,6 @@
-Index: freeradius-server/Make.inc.in
-===================================================================
---- freeradius-server.orig/Make.inc.in
-+++ freeradius-server/Make.inc.in
-@@ -95,7 +95,7 @@ LDFLAGS              = $(OPENSSL_LDFLAGS) $(TALLOC_L
+--- a/Make.inc.in
++++ b/Make.inc.in
+@@ -95,7 +95,7 @@
  
  LOGDIR                = ${logdir}
  RADDBDIR      = ${raddbdir}
@@ -11,11 +9,9 @@ Index: freeradius-server/Make.inc.in
  SBINDIR               = ${sbindir}
  RADIR         = ${radacctdir}
  LIBRADIUS     = $(top_builddir)/src/lib/$(LIBPREFIX)freeradius-radius.la $(TALLOC_LIBS)
-Index: freeradius-server/raddb/radiusd.conf.in
-===================================================================
---- freeradius-server.orig/raddb/radiusd.conf.in
-+++ freeradius-server/raddb/radiusd.conf.in
-@@ -61,7 +61,7 @@ radacctdir = @radacctdir@
+--- a/raddb/radiusd.conf.in
++++ b/raddb/radiusd.conf.in
+@@ -61,7 +61,7 @@
  
  #
  #  name of the running server.  See also the "-n" command-line option.
@@ -24,7 +20,7 @@ Index: freeradius-server/raddb/radiusd.conf.in
  
  #  Location of config and logfiles.
  confdir = ${raddbdir}
-@@ -436,8 +436,8 @@ security {
+@@ -436,8 +436,8 @@
        #  member.  This can allow for some finer-grained access
        #  controls.
        #
@@ -35,10 +31,8 @@ Index: freeradius-server/raddb/radiusd.conf.in
  
        #  Core dumps are a bad thing.  This should only be set to
        #  'yes' if you're debugging a problem with the server.
-Index: freeradius-server/scripts/monit/freeradius.monitrc
-===================================================================
---- freeradius-server.orig/scripts/monit/freeradius.monitrc
-+++ freeradius-server/scripts/monit/freeradius.monitrc
+--- a/scripts/monit/freeradius.monitrc
++++ b/scripts/monit/freeradius.monitrc
 @@ -8,9 +8,9 @@
  #  Totalmem limit should be lowered to 200.0 if none of the 
  #  interpreted language modules or rlm_cache are being used.
@@ -52,3 +46,47 @@ Index: freeradius-server/scripts/monit/freeradius.monitrc
     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
+--- a/raddb/sites-available/control-socket
++++ b/raddb/sites-available/control-socket
+@@ -72,12 +72,12 @@
+       #
+       #  Name of user that is allowed to connect to the control socket.
+       #
+-#     uid = radius
++#     uid = freerad
+       #
+       #  Name of group that is allowed to connect to the control socket.
+       #
+-#     gid = radius
++#     gid = freerad
+       #
+       #  Access mode.
+diff --git a/src/main/radiusd.c b/src/main/radiusd.c
+index 1ae66ec..ee1a711 100644
+--- a/src/main/radiusd.c
++++ b/src/main/radiusd.c
+@@ -93,7 +93,6 @@ int main(int argc, char *argv[])
+       bool display_version = false;
+       int flag = 0;
+       int from_child[2] = {-1, -1};
+-      char *p;
+       fr_state_t *state = NULL;
+
+       /*
+@@ -128,13 +127,7 @@ int main(int argc, char *argv[])
+       main_config.myip.af = AF_UNSPEC;
+       main_config.port = 0;
+       main_config.daemonize = true;
+-
+-      p = strrchr(argv[0], FR_DIR_SEP);
+-      if (!p) {
+-              main_config.name = argv[0];
+-      } else {
+-              main_config.name = p + 1;
+-      }
++      main_config.name = "radiusd";
+
+       /*
+        *      Don't put output anywhere until we get told a little
index 886c023..893d2d1 100644 (file)
@@ -1,3 +1,2 @@
 radiusd-to-freeradius.diff
 disable-dhcp-bydefault.diff
-logrotate-path.diff
index dee6873..9d1867e 100755 (executable)
@@ -107,14 +107,14 @@ endif
        mv config.sub.dist config.sub
 
 #Architecture
-build: patch build-arch build-indep
+build: build-arch build-indep
 
-build-arch: build-arch-stamp patch
+build-arch: patch build-arch-stamp
 build-arch-stamp: config.status
        $(MAKE)
        touch $@
 
-build-indep: build-indep-stamp
+build-indep: patch build-indep-stamp
 build-indep-stamp: config.status
        touch $@
 
diff --git a/debian/source/lintian-overrides b/debian/source/lintian-overrides
new file mode 100644 (file)
index 0000000..ec72c96
--- /dev/null
@@ -0,0 +1,6 @@
+# The RFCs are included in the debian package for reference. This
+# might be a problem in the official Debian archive, but we don't
+# need lintian complaining about it here.
+
+freeradius source: license-problem-non-free-RFC-BCP78 doc/rfc/*
+freeradius source: license-problem-non-free-RFC doc/rfc/*
index 908e269..b53326d 100644 (file)
@@ -1,3 +1,179 @@
+FreeRADIUS 3.0.12 Thur 29 Sep 2016 13:00:00 EDT urgency=medium
+       Feature improvements
+       * Add support for =~ and !~ in update sections.
+         See "man unlang"
+       * Add dictionary.checkpoint.
+       * Simultaneous-Use prints out more information.
+       * Print WARNING in debug mode when packets may be
+         truncated.
+       * Added expansions %{home_server:state} and
+         %{home_server_pool:state}, which show the
+         state of the server / pool.
+       * Mark rlm_sql_freetds as stable.
+       * Make rlm_perl less fragile.  Patch from
+         Herwin Weststrate.
+       * Allow extended attributes to have "encrypt=2"
+       * Update dictionary.aruba.
+       * Add support for EAP-FAST.  This is an isolated
+         feature which does not affect anything else.
+       * Update OpenSSL vulnerability list.  Use a version
+         of OpenSSL released after September 20, 2016.
+       * EAP certificate verification is now done when
+         "verify" is enabled and "ocsp" is disabled.
+       * New dhcpclient and rlm_rad_counter man pages.
+       * Minor abfab and moonshot additions.
+       * Pass CFLAGS through from environment in RPM builds.
+         Allows more custom builds.
+       * Build with Heimdal in addtion to libkrb5.
+
+       Bug fixes
+       * Use correct typedef for older versions of sqlite.
+       * Update mssql schema to add priority
+       * don't complain on /dev/urandom in ldap
+       * fix == operator in update sections
+       * Don't create DHCP strings with many trailing zeros.
+         Patch from Nicolas C.  Fixes #1526.
+       * Allow MS-CHAP change passwords instead of complaining
+         on large buffer.
+       * Allow assignment or equality operator on SQL.
+       * Update aclocal tests for FreeBSD 10.  Patches from
+         Mathieu Simon.
+       * Remove occasional hang in rlm_linelog.
+       * Copy VSAs to inner tunnel for TTLS and PEAP.
+         Fixes #1544
+       * A few minor bugfixes caught in v3.1.x cleanup, and
+         back-ported to v3.0.x.
+       * do_not_respond again works in post-proxy
+       * Allow realm "~^.*$" {} and User-Name with no realm.
+       * Fix leak when creating unknown attributes
+       * Fix Debian / logrotate.
+       * Make OpenSSL error functions thread-safe.
+       * Fix crash with rlm_sql and updating SQL-User-Name.
+       * Debian build updates.
+       * Allow regular expression comparisons in radclient
+         fixes #1574.
+       * Fix memory leak on unknown attributes in detail file
+         reader.
+       * Update example paths in "man" pages when installing
+         them
+       * Build fixes for rlm_mschap.  Fixes #1489.
+       * BSD build fixes.  Patch from issue #1583.
+       * Be more careful about /lib/ when building.
+         Fixes #1585.
+       * Correct ifdef placement error.  Fixes #1572.
+       * Allow for more files in internal "exfile" API
+         So it will be possible to open more than 64
+         "detail" files at the same time.
+       * Remove support for statically built EAP modules.
+         Fixes #1591.
+       * Many fixes to rlm_python from Guillaume Pannatier.
+       * Use correct week adjustment in SQLcounter.
+         Fixes #1608
+       * Minor fixes to allow compilation without DHCP,
+         VMPS, or TCP.
+       * Fix checks for module / config file change on HUP.
+       * Compile regex comparisons when sent via
+         "debug condition".  Fixes #1632.
+       * Update filenames in documentation and examples.
+         Patch from Alan Buxey, #1655.
+       * Don't crash if SQL connection becomes unavailable.
+         Fixes #1640.
+       * Disallow originate_coa when proxy_requests = no
+         Fixes #1684.
+       * Free rad_perlconf_hv in correct perl context.
+         Fixes #1675.
+       * Multiple fixes for Debian builds.  #1510, among
+         others.
+       * Set OpenSSL FIPS compatibility flag when necessary.
+       * Pulled fixes for the build system over from other
+         branches.
+       * Fix OCSP for RADIUS over TLS.
+       * Fix skip_if_ocsp_ok behavior.
+       * Better fixes for systems without closefrom() but
+         which have /proc.  Fixes #1757.
+       * Minor build fixes back-ported from v4.0.x.
+       * build --whout-ascend-binary.  Fixes #1761.
+       * Be more aggressive about not opening new connections
+         in debug mode after CTRL-C.  Address #1604.
+
+FreeRADIUS 3.0.11 Mon 25 Jan 2016 14:00:00 EST urgency=medium
+       Feature improvements
+       * "unlang" comparisons of IP addresses to IP prefixes
+         are now detected, and types automatically cast.
+       * Allow shorthand form of ipv4prefix values e.g. 127/8.
+       * Add "auto_chain" to raddb/mods-available/eap, tls
+         subsection.  This allows the disabling of OpenSSL
+         auto-chaining of certificates.  Which might be wrong.
+       * Added printing of coa and disconnect stats (radmin).
+       * radclient defaults to expecting Access-Accept responses
+         to Status-Server.
+       * Updated dictionary.lancom, dictionary.starent.
+       * Portability fixes for Solaris.
+       * More errors from ntlm_auth gets passed to MS-CHAP.
+       * Update abfab-tr-idp virtual server.
+       * Added "filter_password" in policy.d/filter.  This
+         removes embedded zero bytes in User-Password, for
+         compatibility with broken clients.
+       * The server now issues a WARNING message if duplicate
+         configuration items are found.
+       * TLS can skip the "verify" section if OCSP returns OK.
+         See raddb/mods-available/eap, "skip_if_ocsp_ok".
+       * Set TLS-OCSP-Cert-Valid = yes / no / skipped, which
+         is the result from the OCSP check.
+       * Interoperate with AD and "LmCompatibiltyLevel = 5",
+         by always setting WBC_MSV1_0_ALLOW_MSVCHAPV2 for
+         native winbind in rlm_mschap.
+       * TTLS and PEAP now require "virtual_server" to be a real server.
+       * Print WARNING when TTLS or PEAP identities are spoofed
+         or not properly anonymized.  See RFC 7542 for requirements.
+       * Various rlm_python fixes from Herwin Weststrate.
+       * Allow setting Response-Packet-Type in "Post-Proxy-Type Fail",
+         which is useful when the home server does not respond.
+       * elasticsearch updates from Matthew Newton
+
+       Bug fixes
+       * Fix issue where field nas_type would not be accessible via
+         the %{client:} xlat, for clients loaded from SQL.
+       * Fix compatiblity issues with OpenSSL 1.0.2.  Ignore
+         calls to msg_callback with 'pseudo' content types.
+       * Data type "ipv4prefix" is parsed correctly.
+       * Use correct talloc context in rlm_exec.  Fixes #1338.
+       * Complain in unlang if "else" is used with no previous
+         "if" or "elsif".
+       * Send accounting status packets to the accounting port.
+         Fixes #1364.
+       * Print out CFLAGS when doing "radiusd -Xxv"
+       * Fixed bug with coa/acct stats value #1339. Based on patch from
+         Jorge Pereira.
+       * Fixes for LEAP proxying.  Don't use LEAP!
+       * Fix issue with "directory already exists" seen when doing
+         "make install".
+       * Fixed bug with radmin related to the option "stats detail <filename>"
+       * Complain if the detail file reader does not have permission
+         to read the "detail.work" file.  Fixes #1398
+       * Fixed SoH. Attributes were not being copied to the virtual server.
+       * Used a wrong list to global statistics in "stats".
+       * Create EAP-PWD identity correctly.  Prevents segfaults.
+       * Dynamically validate authentication types for PEAP and EAP-MSCHAPv2.
+       * Fix includes in installed headers.
+       * OpenSSL 1.0.1f and 1.0.1g do NOT calculate TLS 1.2 keys correctly.
+         See raddb/mods-available/eap, "disable_tlsv1_2"
+       * Allow password change to work for MS-CHAP.  This requires 'r=0',
+         because password changes are not retries.
+       * Fix home server fail-over for home servers using TCP and/or RadSec.
+       * Special characters in expanded regexes are now escaped
+         e.g. User-Name containing '.', and comparing /%{User-Name}/,
+         the '.' will now be escaped.  See src/tests/keywords/regex-escape.
+       * Use correct authentication vector when sending Access-Reject replies
+         for RadSec.
+       * Set FreeRADIUS-Proxied-To in TTLS again.  You should use the
+         "inner-tunnel" virtual server, instead of relying on this attribute.
+       * Fix debugging constants in rlm_perl.  Patch from Herwin Weststrate.
+       * Add samba-dev / samba4-dev to debian builds so that rlm_mschap can
+         automatically use the new winbind API.
+       * Automatically skip zero-length attributes when sending packets,
+         instead of erroring out.
+
 FreeRADIUS 3.0.10 Mon 05 Oct 2015 15:00:00 EDT urgency=medium
        Feature improvements
        * Do more optimization of unlang policies.  This makes
@@ -1100,7 +1276,7 @@ FreeRADIUS 3.0.0 Mon  7 Oct 2013 15:48:14 EDT urgency=medium
        * Added EAP-PWD implementation from Dan Harkins
        * Added connection pools for modules. This unifies connection
          management which was previously different for different modules.
-l      * SQL now uses the connection pool.  See mods-available/sql
+       * SQL now uses the connection pool.  See mods-available/sql
        * SQL now supports arbitrary Acct-Status-Types.
          These changes are not compatible with 2.x.
        * SQL now has full support for SQLite.  See raddb/sql/main/sqlite/
index 439aedc..97c47eb 100644 (file)
 
 3d. HINTS
 
-  Customize the /etc/raddb/hints file. This file is used to give users a
-  different login type based on a prefix/suffix of their loginname. For
-  example, logging in as "user" may result in a rlogin session to a Unix
-  system, and logging in as "Puser" could start a PPP session.
+  Customize the /etc/raddb/mods-config/preprocess/hints file. This file is 
+  used to give users different login type based on a prefix/suffix of their 
+  loginname. For example, logging in as "user" may result in a rlogin session 
+  to a Unix system, and logging in as "Puser" could start a PPP session.
 
 3e. HUNTGROUPS
 
-  This is the /etc/raddb/huntgroups file. Here you can define different
-  huntgroups. These can be used to:
+  This is the /etc/raddb/mods-config/preprocess/huntgroups file. Here you can 
+  define different huntgroups. These can be used to:
 
     - restrict access to certain huntgroups to certain users/groups of
       users (define this in the huntgroups file itself)
index 0284538..28f95d8 100644 (file)
@@ -1413,214 +1413,6 @@ a look at all the configuration files, they are heavily documented so you may
 wish to read through them all before making and changes.
 
 
-edit radiusd.conf::
-
-    ----Begin radiusd.conf----
-    ##
-    ## radiusd.conf    -- FreeRADIUS server configuration file.
-    ##
-
-    prefix = /usr/local
-    exec_prefix = ${prefix}
-    sysconfdir = /usr/local/etc/raddb
-    localstatedir = ${prefix}/var
-    sbindir = ${exec_prefix}/sbin
-    logdir = /var/log
-    raddbdir = /usr/local/etc/raddb
-    radacctdir = /var/log/radacct
-
-    #  Location of config and logfiles.
-    confdir = ${raddbdir}
-    run_dir = ${localstatedir}/run/radiusd
-    log_file = ${logdir}/radius.log
-    libdir = ${exec_prefix}/lib
-    pidfile = ${run_dir}/radiusd.pid
-
-    #user = nobody
-    #group = nobody
-
-    max_request_time = 30
-    delete_blocked_requests = no
-    cleanup_delay = 5
-    max_requests = 0
-    bind_address = *
-    port = 0
-    hostname_lookups = no
-    allow_core_dumps = no
-    log_stripped_names = no
-    log_auth = no
-    log_auth_badpass = no
-    log_auth_goodpass = no
-
-    #  The program to execute to do concurrency checks.
-    #checkrad = ${sbindir}/checkrad
-
-    security {
-            max_attributes = 200
-            reject_delay = 0
-            status_server = no
-    }
-
-    proxy_requests  = yes
-    $INCLUDE  ${confdir}/proxy.conf
-
-    $INCLUDE  ${confdir}/clients.conf
-
-    thread pool {
-            start_servers = 5
-            max_servers = 32
-            min_spare_servers = 3
-            max_spare_servers = 10
-            max_requests_per_server = 0
-    }
-
-    modules {
-
-            ldap {
-            server = "localhost"
-            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}})
-    (objectclass=radiusprofile)"
-            start_tls = no
-            tls_mode = no
-            #default_profile = "uid=dial,ou=profiles,ou=radius,dc=mydomain,dc=com"
-            #profile_attribute = "radiusProfileDn"
-            dictionary_mapping = ${raddbdir}/ldap.attrmap
-            ldap_cache_timeout = 120
-            ldap_cache_size = 0
-            ldap_connections_number = 10
-            #password_header = "{clear}"
-            password_attribute = userPassword
-            groupname_attribute = radiusGroupName
-            groupmembership_filter = "(&(uid=%{%{Stripped-User-Name}:-%{User-Name}}))
-    (objectclass=radiusProfile)"
-            groupmembership_attribute = radiusGroupName
-            timeout = 3
-            timelimit = 5
-            net_timeout = 1
-            compare_check_items = no
-            #access_attr_used_for_allow = yes
-            }
-
-            realm suffix {
-                    format = suffix
-                    delimiter = "@"
-            }
-
-            preprocess {
-                    huntgroups = ${confdir}/huntgroups
-                    #hints = ${confdir}/hints
-                    with_ascend_hack = no
-                    ascend_channels_per_line = 23
-                    with_ntdomain_hack = no
-                    with_specialix_jetstream_hack = no
-                    with_cisco_vsa_hack = no
-            }
-
-            files {
-                    usersfile = ${confdir}/users
-                    #acctusersfile = ${confdir}/acct_users
-                    compat = no
-                    #use old style users
-            }
-            # regular detail files
-            detail detail1 {
-                    filename = ${radacctdir}/%{Client-IP-Address}/detail-%Y%m%d
-                    permissions = 0600
-                    dir_permissions = 0755
-            }
-            # temp detail file to replicate to accountrad
-            detail detail2 {
-                    filename = ${radacctdir}/detail-combined
-                    permissions = 0600
-                    dir_permissions = 0755
-                    locking = yes
-            }
-
-            #radutmp {
-            #  filename = ${logdir}/radutmp
-            #  permissions =  0600
-            #  caller_id = "yes"
-            #}
-
-            #radutmp sradutmp {
-            #  filename = ${logdir}/sradutmp
-            #  permissions =  0644
-            #  caller_id = "no"
-            #}
-
-            #attr_filter {
-            #  attrsfile = ${confdir}/attrs
-            #}
-
-
-            # The "always" module is here for debugging purposes. Each
-            # instance simply returns the same result, always, without
-            # doing anything.
-            always fail {
-                    rcode = fail
-            }
-            always reject {
-                    rcode = reject
-            }
-            always ok {
-                    rcode = ok
-                    simulcount = 0
-                    mpp = no
-            }
-
-            #
-            #  The 'expression' module current has no configuration.
-            expr {
-            }
-
-    }
-
-    instantiate {
-            expr
-    }
-
-    authorize {
-            preprocess
-            suffix
-            files
-            ldap
-    }
-
-    authenticate {
-            authtype LDAP {
-                    ldap
-            }
-    }
-
-    preacct {
-            preprocess
-            suffix
-            files
-    }
-
-    accounting {
-            acct_unique
-            detail1
-            detail2
-            #radutmp
-            #sradutmp
-    }
-
-
-    #session {
-            #radutmp
-    #}
-
-    #post-auth {
-            #  Get an address from the IP Pool.
-            #main_pool
-    #}
-    ----End radiusd.conf----
-
-
 edit huntgroups to specify a NAS to a huntgroup::
 
     ----Begin huntgroups----
index 93b937c..c3373cc 100644 (file)
@@ -2,9 +2,8 @@ Example configuration for logstash/elasticsearch
 ================================================
 
 So you've got all these RADIUS logs, but how do you analyse them? What is the
-easiest way to query the logs, find out when a client connected or
-disconnected, or view the top ten clients logging into the system over the last
-six hours?
+easiest way to query the logs, find out when a client connected or disconnected,
+or view the top ten clients logging into the system over the last six hours?
 
 The logstash/elasticsearch/kibana stack is designed and built to do just that.
 elasticsearch is a search engine; logstash is commonly used to feed data in,
@@ -15,13 +14,15 @@ in a short amount of time by any competent sysadmin. Then comes getting the
 logs in.
 
 This directory contains the following files as a starting point for feeding
-RADIUS logs into elasticsearch via logstash.
+RADIUS logs into elasticsearch via logstash, then sample dashboards for Kibana
+to explore the data.
 
 Files
 -----
 
 Please note that all files should be reviewed before use to determine if they
-are suitable for your configuration/system.
+are suitable for your configuration/system, especially if you are integrating
+this into an existing logstash/elasticsearch setup.
 
 radius-mapping.sh
 
@@ -34,12 +35,12 @@ radius-mapping.sh
   This shell script (which just runs curl) pushes a template mapping into the
   elasticsearch cluster.
 
-
-radius.conf
+logstash-radius.conf
 
   A sample configuration file for logstash that parses RADIUS 'detail' files.
   It processes these by joining each record onto one line, then splitting the
-  tab-delimited key-value pairs out.
+  tab-delimited key-value pairs out. Some additional data is then extracted
+  from certain key attributes.
 
   The file will need to be edited at least to set the input method: for
   experimentation the given input (stdin) may be used. If logstash is running on
@@ -47,6 +48,27 @@ radius.conf
   input such as log-courier or logstash-forwarder may be better to get the data
   over the network to the logstash server.
 
+  It would be best to use an input method that can join the multiple lines of
+  the detail file together and feed them to logstash as a single entry, rather
+  than using the logstash multiline filter.
+
+log-courier.conf
+
+  An example configuration for the log-courier feeder.
+
+kibana4-dashboard.json
+
+  Basic RADIUS dashboard for Kibana4.
+
+  To import the dashboard first create a new index called "radius-*" in
+  Settings/Indices. Then go to Kibana's Settings page, "Objects" and "Import".
+  Once imported open the "RADIUS detail" dashboard.
+
+kibana3-dashboard.json
+
+  Basic RADIUS dashboard for Kibana3. To import the dashboard go to Load,
+  Advanced and "Choose File".
+
 
 Example usage
 -------------
@@ -55,7 +77,7 @@ Install mapping (only needs to be done once):
 $ ./radius-mapping.sh
 
 Feed a detail file in:
-$ /path/to/logstash -f radius.conf < acct-detail
+$ /path/to/logstash -f logstash-radius.conf < acct-detail
 
 
 See also
@@ -63,8 +85,15 @@ See also
 
 elasticsearch web site: http://www.elastic.co/
 
+The configuration examples presented here have been tested with the
+following software versions (note that elasticsearch 2.x may not yet
+work with this config).
 
+  elasticsearch 1.7.4
+  logstash 1.4.5
+  kibana 4.1.2
+  kibana 3.1.0
 
 Matthew Newton
-April 2015
+January 2016
 
diff --git a/doc/schemas/logstash/kibana3-dashboard.json b/doc/schemas/logstash/kibana3-dashboard.json
new file mode 100644 (file)
index 0000000..498a1c8
--- /dev/null
@@ -0,0 +1,476 @@
+{
+  "title": "RADIUS detail",
+  "services": {
+    "query": {
+      "list": {
+        "0": {
+          "query": "*",
+          "alias": "",
+          "color": "#584477",
+          "id": 0,
+          "pin": false,
+          "type": "lucene",
+          "enable": true
+        },
+        "1": {
+          "id": 1,
+          "type": "lucene",
+          "query": "Acct-Status-Type:Start",
+          "alias": "Accounting Start",
+          "color": "#629E51",
+          "pin": false,
+          "enable": true
+        },
+        "2": {
+          "id": 2,
+          "color": "#6ED0E0",
+          "alias": "",
+          "pin": false,
+          "type": "lucene",
+          "enable": true,
+          "query": "Acct-Status-Type:Interim-Update"
+        },
+        "3": {
+          "id": 3,
+          "color": "#BF1B00",
+          "alias": "",
+          "pin": false,
+          "type": "lucene",
+          "enable": true,
+          "query": "Acct-Status-Type:Stop"
+        }
+      },
+      "ids": [
+        0,
+        1,
+        2,
+        3
+      ]
+    },
+    "filter": {
+      "list": {
+        "0": {
+          "type": "time",
+          "field": "@timestamp",
+          "from": "now-7d",
+          "to": "now",
+          "mandate": "must",
+          "active": true,
+          "alias": "",
+          "id": 0
+        }
+      },
+      "ids": [
+        0
+      ]
+    }
+  },
+  "rows": [
+    {
+      "title": "Time series",
+      "height": "200px",
+      "editable": true,
+      "collapse": false,
+      "collapsable": true,
+      "panels": [
+        {
+          "span": 9,
+          "editable": true,
+          "type": "histogram",
+          "loadingEditor": false,
+          "mode": "count",
+          "time_field": "@timestamp",
+          "value_field": null,
+          "x-axis": true,
+          "y-axis": true,
+          "scale": 1,
+          "y_format": "none",
+          "grid": {
+            "max": null,
+            "min": 0
+          },
+          "queries": {
+            "mode": "selected",
+            "ids": [
+              1,
+              2,
+              3
+            ]
+          },
+          "annotate": {
+            "enable": false,
+            "query": "*",
+            "size": 20,
+            "field": "_type",
+            "sort": [
+              "_score",
+              "desc"
+            ]
+          },
+          "auto_int": true,
+          "resolution": 100,
+          "interval": "1h",
+          "intervals": [
+            "auto",
+            "1s",
+            "1m",
+            "5m",
+            "10m",
+            "30m",
+            "1h",
+            "3h",
+            "12h",
+            "1d",
+            "1w",
+            "1y"
+          ],
+          "lines": false,
+          "fill": 0,
+          "linewidth": 3,
+          "points": false,
+          "pointradius": 5,
+          "bars": true,
+          "stack": true,
+          "spyable": true,
+          "zoomlinks": true,
+          "options": true,
+          "legend": true,
+          "show_query": true,
+          "interactive": true,
+          "legend_counts": true,
+          "timezone": "browser",
+          "percentage": false,
+          "zerofill": true,
+          "derivative": false,
+          "tooltip": {
+            "value_type": "cumulative",
+            "query_as_alias": true
+          },
+          "title": "RADIUS Accounting data"
+        },
+        {
+          "error": false,
+          "span": 3,
+          "editable": true,
+          "type": "terms",
+          "loadingEditor": false,
+          "field": "NAS-Identifier",
+          "exclude": [],
+          "missing": false,
+          "other": false,
+          "size": 20,
+          "order": "count",
+          "style": {
+            "font-size": "10pt"
+          },
+          "donut": false,
+          "tilt": false,
+          "labels": true,
+          "arrangement": "horizontal",
+          "chart": "pie",
+          "counter_pos": "above",
+          "spyable": true,
+          "queries": {
+            "mode": "selected",
+            "ids": [
+              1
+            ]
+          },
+          "tmode": "terms",
+          "tstat": "total",
+          "valuefield": "",
+          "title": "Sessions by NAS"
+        }
+      ],
+      "notice": false
+    },
+    {
+      "title": "Graphs",
+      "height": "200px",
+      "editable": true,
+      "collapse": false,
+      "collapsable": true,
+      "panels": [
+        {
+          "error": false,
+          "span": 3,
+          "editable": true,
+          "type": "terms",
+          "loadingEditor": false,
+          "field": "Calling-Station-Id",
+          "exclude": [],
+          "missing": false,
+          "other": false,
+          "size": 10,
+          "order": "count",
+          "style": {
+            "font-size": "10pt"
+          },
+          "donut": false,
+          "tilt": false,
+          "labels": true,
+          "arrangement": "horizontal",
+          "chart": "table",
+          "counter_pos": "above",
+          "spyable": true,
+          "queries": {
+            "mode": "selected",
+            "ids": [
+              1
+            ]
+          },
+          "tmode": "terms",
+          "tstat": "total",
+          "valuefield": "",
+          "title": "Top Calling-Station-Id"
+        },
+        {
+          "error": false,
+          "span": 3,
+          "editable": true,
+          "type": "terms",
+          "loadingEditor": false,
+          "field": "Called-Station-Id",
+          "exclude": [],
+          "missing": false,
+          "other": false,
+          "size": 10,
+          "order": "count",
+          "style": {
+            "font-size": "10pt"
+          },
+          "donut": false,
+          "tilt": false,
+          "labels": true,
+          "arrangement": "horizontal",
+          "chart": "table",
+          "counter_pos": "above",
+          "spyable": true,
+          "queries": {
+            "mode": "selected",
+            "ids": [
+              1
+            ]
+          },
+          "tmode": "terms",
+          "tstat": "total",
+          "valuefield": "",
+          "title": "TopN Called-Station-Id"
+        },
+        {
+          "error": false,
+          "span": 3,
+          "editable": true,
+          "type": "terms",
+          "loadingEditor": false,
+          "field": "User-Name",
+          "exclude": [],
+          "missing": false,
+          "other": false,
+          "size": 10,
+          "order": "max",
+          "style": {
+            "font-size": "10pt"
+          },
+          "donut": false,
+          "tilt": false,
+          "labels": true,
+          "arrangement": "horizontal",
+          "chart": "table",
+          "counter_pos": "above",
+          "spyable": true,
+          "queries": {
+            "mode": "all",
+            "ids": [
+              0,
+              1,
+              2,
+              3
+            ]
+          },
+          "tmode": "terms_stats",
+          "tstat": "max",
+          "valuefield": "Acct-Output-Octets_long",
+          "title": "TopN data Output"
+        },
+        {
+          "error": false,
+          "span": 3,
+          "editable": true,
+          "type": "terms",
+          "loadingEditor": false,
+          "field": "User-Name",
+          "exclude": [],
+          "missing": false,
+          "other": false,
+          "size": 10,
+          "order": "max",
+          "style": {
+            "font-size": "10pt"
+          },
+          "donut": false,
+          "tilt": false,
+          "labels": true,
+          "arrangement": "horizontal",
+          "chart": "table",
+          "counter_pos": "above",
+          "spyable": true,
+          "queries": {
+            "mode": "all",
+            "ids": [
+              0,
+              1,
+              2,
+              3
+            ]
+          },
+          "tmode": "terms_stats",
+          "tstat": "max",
+          "valuefield": "Acct-Input-Octets_long",
+          "title": "TopN Data Input"
+        }
+      ],
+      "notice": false
+    },
+    {
+      "title": "Table",
+      "height": "150px",
+      "editable": true,
+      "collapse": false,
+      "collapsable": true,
+      "panels": [
+        {
+          "error": false,
+          "span": 12,
+          "editable": true,
+          "type": "table",
+          "loadingEditor": false,
+          "size": 100,
+          "pages": 5,
+          "offset": 0,
+          "sort": [
+            "@timestamp",
+            "asc"
+          ],
+          "overflow": "min-height",
+          "fields": [
+            "timestamp",
+            "User-Name",
+            "Calling-Station-Id",
+            "Called-Station-Id",
+            "Framed-IP-Address",
+            "NAS-Identifier"
+          ],
+          "highlight": [],
+          "sortable": true,
+          "header": true,
+          "paging": true,
+          "field_list": false,
+          "all_fields": false,
+          "trimFactor": 500,
+          "localTime": false,
+          "timeField": "@timestamp",
+          "spyable": true,
+          "queries": {
+            "mode": "all",
+            "ids": [
+              0,
+              1,
+              2,
+              3
+            ]
+          },
+          "style": {
+            "font-size": "9pt"
+          },
+          "normTimes": true,
+          "title": "RADIUS data"
+        }
+      ],
+      "notice": false
+    }
+  ],
+  "editable": true,
+  "failover": false,
+  "index": {
+    "interval": "day",
+    "pattern": "[radius-]YYYY.MM.DD",
+    "default": "[radius-]YYYY.MM.DD",
+    "warm_fields": false
+  },
+  "style": "dark",
+  "panel_hints": true,
+  "pulldowns": [
+    {
+      "type": "query",
+      "collapse": true,
+      "notice": false,
+      "enable": true,
+      "query": "*",
+      "pinned": true,
+      "history": [
+        "Acct-Status-Type:Stop",
+        "Acct-Status-Type:Interim-Update",
+        "Acct-Status-Type:Start",
+        "*"
+      ],
+      "remember": 10
+    },
+    {
+      "type": "filtering",
+      "collapse": true,
+      "notice": true,
+      "enable": true
+    }
+  ],
+  "nav": [
+    {
+      "type": "timepicker",
+      "collapse": false,
+      "notice": false,
+      "enable": true,
+      "status": "Stable",
+      "time_options": [
+        "5m",
+        "15m",
+        "1h",
+        "6h",
+        "12h",
+        "24h",
+        "2d",
+        "7d",
+        "30d"
+      ],
+      "refresh_intervals": [
+        "5s",
+        "10s",
+        "30s",
+        "1m",
+        "5m",
+        "15m",
+        "30m",
+        "1h",
+        "2h",
+        "1d"
+      ],
+      "timefield": "@timestamp",
+      "now": true,
+      "filter_id": 0
+    }
+  ],
+  "loader": {
+    "save_gist": false,
+    "save_elasticsearch": true,
+    "save_local": true,
+    "save_default": true,
+    "save_temp": true,
+    "save_temp_ttl_enable": true,
+    "save_temp_ttl": "30d",
+    "load_gist": false,
+    "load_elasticsearch": true,
+    "load_elasticsearch_size": 20,
+    "load_local": false,
+    "hide": false
+  },
+  "refresh": false
+}
diff --git a/doc/schemas/logstash/kibana4-dashboard.json b/doc/schemas/logstash/kibana4-dashboard.json
new file mode 100644 (file)
index 0000000..eb7930e
--- /dev/null
@@ -0,0 +1,123 @@
+[
+  {
+    "_id": "RADIUS-detail",
+    "_type": "dashboard",
+    "_source": {
+      "title": "RADIUS detail",
+      "hits": 0,
+      "description": "",
+      "panelsJSON": "[{\"col\":5,\"id\":\"RADIUS-unique-User-Name-by-day\",\"row\":1,\"size_x\":4,\"size_y\":4,\"type\":\"visualization\"},{\"col\":1,\"columns\":[\"User-Name\",\"Calling-Station-Id\",\"Called-Station-Id\",\"Framed-IP-Address\",\"NAS-Identifier\"],\"id\":\"RADIUS-data\",\"row\":5,\"size_x\":8,\"size_y\":4,\"sort\":[\"@timestamp\",\"desc\"],\"type\":\"search\"},{\"col\":1,\"id\":\"RADIUS-accounting-packets-histogram\",\"row\":1,\"size_x\":4,\"size_y\":4,\"type\":\"visualization\"},{\"col\":9,\"id\":\"RADIUS-table-topN-data-transferred-by-User-Name\",\"row\":1,\"size_x\":4,\"size_y\":4,\"type\":\"visualization\"},{\"id\":\"RADIUS-Sessions-per-NAS\",\"type\":\"visualization\",\"size_x\":4,\"size_y\":4,\"col\":9,\"row\":5}]",
+      "version": 1,
+      "timeRestore": true,
+      "timeTo": "now",
+      "timeFrom": "now-7d",
+      "kibanaSavedObjectMeta": {
+        "searchSourceJSON": "{\"filter\":[{\"query\":{\"query_string\":{\"analyze_wildcard\":true,\"query\":\"*\"}}}]}"
+      }
+    }
+  },
+  {
+    "_id": "RADIUS-Accounting-Start-data",
+    "_type": "search",
+    "_source": {
+      "title": "RADIUS Accounting-Start data",
+      "description": "",
+      "hits": 0,
+      "columns": [
+        "User-Name",
+        "Calling-Station-Id",
+        "Called-Station-Id",
+        "Framed-IP-Address",
+        "NAS-Identifier"
+      ],
+      "sort": [
+        "@timestamp",
+        "desc"
+      ],
+      "version": 1,
+      "kibanaSavedObjectMeta": {
+        "searchSourceJSON": "{\"index\":\"radius-*\",\"query\":{\"query_string\":{\"analyze_wildcard\":true,\"query\":\"*\"}},\"highlight\":{\"pre_tags\":[\"@kibana-highlighted-field@\"],\"post_tags\":[\"@/kibana-highlighted-field@\"],\"fields\":{\"*\":{}},\"fragment_size\":2147483647},\"filter\":[{\"meta\":{\"negate\":false,\"index\":\"radius-*\",\"key\":\"Acct-Status-Type\",\"value\":\"Start\",\"disabled\":false},\"query\":{\"match\":{\"Acct-Status-Type\":{\"query\":\"Start\",\"type\":\"phrase\"}}}}]}"
+      }
+    }
+  },
+  {
+    "_id": "RADIUS-data",
+    "_type": "search",
+    "_source": {
+      "title": "RADIUS data",
+      "description": "",
+      "hits": 0,
+      "columns": [
+        "User-Name",
+        "Calling-Station-Id",
+        "Called-Station-Id",
+        "Framed-IP-Address",
+        "NAS-Identifier"
+      ],
+      "sort": [
+        "@timestamp",
+        "desc"
+      ],
+      "version": 1,
+      "kibanaSavedObjectMeta": {
+        "searchSourceJSON": "{\"index\":\"radius-*\",\"query\":{\"query_string\":{\"analyze_wildcard\":true,\"query\":\"*\"}},\"highlight\":{\"pre_tags\":[\"@kibana-highlighted-field@\"],\"post_tags\":[\"@/kibana-highlighted-field@\"],\"fields\":{\"*\":{}},\"fragment_size\":2147483647},\"filter\":[]}"
+      }
+    }
+  },
+  {
+    "_id": "RADIUS-unique-User-Name-by-day",
+    "_type": "visualization",
+    "_source": {
+      "title": "RADIUS unique User-Name by day",
+      "visState": "{\n  \"type\": \"histogram\",\n  \"params\": {\n    \"shareYAxis\": true,\n    \"addTooltip\": true,\n    \"addLegend\": true,\n    \"scale\": \"linear\",\n    \"mode\": \"stacked\",\n    \"times\": [],\n    \"addTimeMarker\": false,\n    \"defaultYExtents\": false,\n    \"setYExtents\": false,\n    \"yAxis\": {}\n  },\n  \"aggs\": [\n    {\n      \"id\": \"1\",\n      \"type\": \"cardinality\",\n      \"schema\": \"metric\",\n      \"params\": {\n        \"field\": \"User-Name\"\n      }\n    },\n    {\n      \"id\": \"2\",\n      \"type\": \"date_histogram\",\n      \"schema\": \"segment\",\n      \"params\": {\n        \"field\": \"@timestamp\",\n        \"interval\": \"d\",\n        \"customInterval\": \"2h\",\n        \"min_doc_count\": 1,\n        \"extended_bounds\": {}\n      }\n    },\n    {\n      \"id\": \"3\",\n      \"type\": \"terms\",\n      \"schema\": \"group\",\n      \"params\": {\n        \"field\": \"User-Name\",\n        \"size\": 50,\n        \"order\": \"desc\",\n        \"orderBy\": \"1\"\n      }\n    }\n  ],\n  \"listeners\": {}\n}",
+      "description": "",
+      "version": 1,
+      "kibanaSavedObjectMeta": {
+        "searchSourceJSON": "{\n  \"filter\": []\n}"
+      },
+      "savedSearchId": "RADIUS-data"
+    }
+  },
+  {
+    "_id": "RADIUS-accounting-packets-histogram",
+    "_type": "visualization",
+    "_source": {
+      "title": "RADIUS accounting packets histogram",
+      "visState": "{\"type\":\"histogram\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"scale\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"Acct-Status-Type\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+      "description": "",
+      "savedSearchId": "RADIUS-data",
+      "version": 1,
+      "kibanaSavedObjectMeta": {
+        "searchSourceJSON": "{\"filter\":[]}"
+      }
+    }
+  },
+  {
+    "_id": "RADIUS-table-topN-data-transferred-by-User-Name",
+    "_type": "visualization",
+    "_source": {
+      "title": "RADIUS table topN data transferred by User-Name",
+      "visState": "{\"type\":\"table\",\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMeticsAtAllLevels\":false},\"aggs\":[{\"id\":\"1\",\"type\":\"max\",\"schema\":\"metric\",\"params\":{\"field\":\"Acct-Output-Octets_long\"}},{\"id\":\"2\",\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"User-Name\",\"size\":10,\"order\":\"desc\",\"orderBy\":\"1\"}},{\"id\":\"3\",\"type\":\"max\",\"schema\":\"metric\",\"params\":{\"field\":\"Acct-Input-Octets_long\"}}],\"listeners\":{}}",
+      "description": "",
+      "savedSearchId": "RADIUS-data",
+      "version": 1,
+      "kibanaSavedObjectMeta": {
+        "searchSourceJSON": "{\"filter\":[]}"
+      }
+    }
+  },
+  {
+    "_id": "RADIUS-Sessions-per-NAS",
+    "_type": "visualization",
+    "_source": {
+      "title": "RADIUS Sessions per NAS",
+      "visState": "{\"type\":\"pie\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"isDonut\":false},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"NAS-Identifier\",\"size\":20,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}",
+      "description": "",
+      "savedSearchId": "RADIUS-Accounting-Start-data",
+      "version": 1,
+      "kibanaSavedObjectMeta": {
+        "searchSourceJSON": "{\"filter\":[]}"
+      }
+    }
+  }
+]
diff --git a/doc/schemas/logstash/log-courier.conf b/doc/schemas/logstash/log-courier.conf
new file mode 100644 (file)
index 0000000..95e1676
--- /dev/null
@@ -0,0 +1,56 @@
+# Example log-courier configuration file for RADIUS detail files.
+#
+{
+       "general": {
+               "persist directory": "/var/lib/log-courier",
+               "log syslog": true,
+               "log stdout": false,
+               "admin listen address": "unix:/var/run/log-courier/admin.socket"
+       },
+
+       "network": {
+               "transport": "tcp",
+               "reconnect": 10,
+
+               # Servers to connect to.
+               #
+               "servers": [
+                       "logstash1.example:5140",
+                       "logstash2.example:5140"
+               ]
+       },
+
+       "files": [
+               {
+                       # Match RADIUS detail files, but not anything that has
+                       # been gzipped.
+                       #
+                       "paths": [ "/var/log/radius/radacct/*/detail-????????" ],
+
+                       # Add a type:"radiusdetail" field to the data so that
+                       # logstash can tell what type of data this is (in case
+                       # log-courier is being used for other data as well).
+                       #
+                       "fields": {
+                               "type": "radiusdetail"
+                       },
+
+                       # Stop watching a file if nothing has been written in 12h.
+                       #
+                       "dead time": "12h",
+
+                       # Process multilines. If this is being used then the
+                       # "multiline" section should be commented out from the
+                       # logstash configuration. Logstash can then also be run
+                       # with multiple workers (using -w).
+                       #
+                       "codec": {
+                               "name": "multiline",
+                               "pattern": "^[A-Z\t]",
+                               "negate": false,
+                               "what": "next"
+                       }
+               }
+       ]
+}
+
diff --git a/doc/schemas/logstash/logstash-radius.conf b/doc/schemas/logstash/logstash-radius.conf
new file mode 100644 (file)
index 0000000..8b277a0
--- /dev/null
@@ -0,0 +1,217 @@
+# logstash configuration to process RADIUS detail files
+#
+# Matthew Newton
+# January 2016
+# 
+# RADIUS "detail" files are textual representations of the RADIUS
+# packets, and are written to disk by e.g. FreeRADIUS. They look
+# something like the following, with the timestamp on the first
+# line then all attributes/values tab-indented.
+#
+#      Tue Mar 10 15:32:24 2015
+#              Packet-Type = Access-Request
+#              User-Name = "test@example.com"
+#              Calling-Station-Id = "01-02-03-04-05-06"
+#              Called-Station-Id = "aa-bb-cc-dd-ee-ff:myssid"
+#              NAS-Port = 10
+#              NAS-IP-Address = 10.9.0.4
+#              NAS-Identifier = "Wireless-Controller-1"
+#              Service-Type = Framed-User
+#              NAS-Port-Type = Wireless-802.11
+#
+
+
+
+# Example input - read data from a file. This can be useful for
+# testing, but usually not so much for live service. For example,
+# to read in a detail file with this input you could use:
+#
+#   /opt/logstash/bin/logstash -v -f logstash-radius.conf < detailfile
+
+input {
+       stdin {
+               type => radiusdetail
+       }
+}
+
+# Moving into production will likely need something more reliable.
+# There are many input methods, an example here using log-courier
+# (which supports client-site multiline processing and does not
+# lose log events if logstash is restarted).
+
+# input {
+#      courier {
+#              port => 5140
+#              transport => "tcp"
+#      }
+# }
+
+
+
+# Filter stage. Here we take the raw logs and process them into
+# something structured ready to index. Each attribute is stored as
+# a separate field in the output document.
+
+filter {
+
+       if [type] == "radiusdetail" {
+
+               # If you are using a log feeder that can join
+               # multiple lines together then that is preferrable
+               # to using multiline here, because this can not be
+               # used with threaded logstash (i.e. -w<n> at
+               # startup).
+
+               # In that case you should comment out the following
+               # section. For example, see the log-courier
+               # configuration configuration in this directory.
+
+               multiline {
+                       pattern => "^[A-Z\t]"
+                       negate => false
+                       what => "next"
+               }
+
+               # Pull off the timestamp at the start of the
+               # detail record. Note there may be additional data
+               # after it that has been added by the local admin,
+               # so stop at a newline OR a tab.
+
+               grok {
+                       match => [ "message", "^(?<timestamp>[^\n\t]+)[\n\t]" ]
+               }
+
+               # Create the @timestamp field.
+
+               date {
+                       match => [ "timestamp", "EEE MMM dd HH:mm:ss yyyy",
+                                               "EEE MMM  d HH:mm:ss yyyy" ]
+               }
+
+               # Split the attributes and values into fields.
+               # This is the bulk of processing that adds all of
+               # the RADIUS attributes as elasticsearch fields.
+
+               kv {
+                       field_split => "\n"
+                       source => "message"
+                       trim => "\" "
+                       trimkey => "\t "
+               }
+
+               # Now we try and add some useful additional
+               # information. If certain fields can be broken
+               # down into components then do that here and add
+               # the data as sub-fields. For example,
+               # Called-Station-Id might be able to be broken
+               # down to Called-Station-Id_mac and Called-Station-Id_ssid
+               # on some wireless systems, or to _ip and _port
+               # with a VPN.
+
+               # Multiple calls to grok otherwise it can stop
+               # processing once it has matched one field, but
+               # e.g. you want to pull both IP and port out of
+               # the same field in two different regex's.
+
+               # Pull out some IP addresses as field_ip:
+
+               grok {
+                       break_on_match => false
+                       tag_on_failure => []
+                       match => [
+                               "Framed-IP-Address", "^(?<Framed-IP-Address_ip>\d+\.\d+\.\d+\.\d+$)",
+                               "NAS-IP-Address", "^(?<NAS-IP-Address_ip>\d+\.\d+\.\d+\.\d+$)",
+                               "Calling-Station-Id", "^(?<Calling-Station-Id_ip>\d+\.\d+\.\d+\.\d+)",
+                               "Called-Station-Id", "^(?<Called-Station-Id_ip>\d+\.\d+\.\d+\.\d+)"
+                       ]
+               }
+
+               # Split User-Name, Operator-Name, and pull out
+               # some IP ports if they are there:
+
+               grok {
+                       break_on_match => false
+                       tag_on_failure => []
+                       match => [
+                               "User-Name", "^(?<User-Name_username>[^@]+)?(?:@(?<User-Name_realm>[^@]+))$",
+                               "Operator-Name", "^(?<Operator-Name_id>.)(?<Operator-Name_value>.+)$",
+
+                               "Calling-Station-Id", "\[(?<Calling-Station-Id_port>\d+)\]$",
+                               "Called-Station-Id", "\[(?<Called-Station-Id_port>\d+)\]$"
+                       ]
+               }
+
+               # Extract MAC addresses (and SSIDs if there).
+               # MAC address matching here is lazy, but should be
+               # good enough.
+
+               grok {
+                       break_on_match => false
+                       tag_on_failure => []
+                       match => [
+                               "Calling-Station-Id", "^(?<Calling-Station-Id_mac>[a-fA-F0-9:-]{17})$",
+                               "Calling-Station-Id", "^(?<Calling-Station-Id_mac>[a-fA-F0-9\.]{14})$",
+                               "Calling-Station-Id", "^(?<Calling-Station-Id_mac>[a-fA-F0-9]{12})$",
+
+                               "Called-Station-Id", "^(?<Called-Station-Id_mac>[a-fA-F0-9:-]{17})(?::(?<Called-Station-Id_ssid>.*))?$",
+                               "Called-Station-Id", "^(?<Called-Station-Id_mac>[a-fA-F0-9\.]{14})(?::(?<Called-Station-Id_ssid>.*))?$",
+                               "Called-Station-Id", "^(?<Called-Station-Id_mac>[a-fA-F0-9]{12})(?::(?<Called-Station-Id_ssid>.*))?$"
+                       ]
+               }
+
+               # With the optional sanitize_mac plugin, it's
+               # possible to make sure all MAC addresses look the
+               # same, which has obvious benefits.
+               #
+               # https://github.com/mcnewton/elk/blob/master/logstash-filters/sanitize_mac.rb
+
+               # sanitize_mac {
+               #       match => {
+               #               "Called-Station-Id_mac" => "Called-Station-Id_mac"
+               #               "Calling-Station-Id_mac" => "Calling-Station-Id_mac"
+               #               }
+               #       separator => ":"
+               #       fixcase => "lower"
+               # }
+
+
+               # Gigawords presents an issue because the 64-bit
+               # value is split across two attributes. Combine
+               # them both back into a single attribute so that
+               # the full value is available to use.
+
+               if ([Acct-Input-Octets]) {
+                       ruby {
+                               code => "event['Acct-Input-Octets_long'] =
+                                       event['Acct-Input-Octets'].to_i + ( event['Acct-Input-Gigawords'] ? (event['Acct-Input-Gigawords'].to_i * (2**32)) : 0)"
+                       }
+               }
+
+               if ([Acct-Output-Octets]) {
+                       ruby {
+                               code => "event['Acct-Output-Octets_long'] =
+                                       event['Acct-Output-Octets'].to_i + ( event['Acct-Output-Gigawords'] ? (event['Acct-Output-Gigawords'].to_i * (2**32)) : 0)"
+                       }
+               }
+
+       }
+}
+
+
+
+# Output data to the local elasticsearch cluster (called
+# "elasticsearch") using type "detail" in index "radius-DATE".
+
+output {
+       if [type] == "radiusdetail" {
+               elasticsearch {
+                       host => localhost
+                       protocol => http
+                       cluster => elasticsearch
+                       index_type => "detail"
+                       index => "radius-%{+YYYY.MM.dd}"
+                       flush_size => 1000
+               }
+       }
+}
+
old mode 100644 (file)
new mode 100755 (executable)
index 25f7071..f3f4724
@@ -4,8 +4,34 @@
 # Matthew Newton
 # April 2015
 
-# This should be run on an elasticsearch node. Alternatively, adjust
-# the curl URI below.
+# This should be run on an elasticsearch node. Alternatively,
+# adjust the curl URI below.
+
+# The template will be called "radius", and will apply to all
+# indices prefixed with "radius-" that contain data type "detail".
+# As not all RADIUS attributes are known to begin with it has the
+# following starting point that can be modified to suit the local
+# configuration:
+#
+#   Acct-Input- or Acct-Output- attributes are numbers;
+#   Acct-Session-Time is a number;
+#   Everything else is a string.
+
+# Additionally, the supplied logstash config will try and extract
+# MAC addresses, IP addresses and ports from the data. These are
+# stored with suffixes on the respective attribute. For example,
+# an attribute
+#
+#   Called-Station-Id := "10.0.4.6[4500]"
+#
+# will be broken down into the following fields in elasticsearch:
+#
+#   Called-Station-Id = "10.0.4.6[4500]"
+#   Called-Station-Id_ip = "10.0.4.6"
+#   Called-Station-Id_port = "4500"
+#
+# This mapping ensures that these have an appropriate data type.
+
 
 curl -XPUT '127.0.0.1:9200/_template/radius' -d '
 {
@@ -13,26 +39,65 @@ curl -XPUT '127.0.0.1:9200/_template/radius' -d '
   "order":0,
   "mappings":{
     "detail":{
-      "dynamic_templates":[
-        { "keep_message":{
-            "match":"message",
-            "mapping":{
-              "type":"string",
-              "index":"analyzed"
+
+      "properties": {
+        "@timestamp": { "format": "dateOptionalTime", "type": "date" },
+        "@version": { "type" : "string" },
+        "message": { "type" : "string" },
+        "Acct-Session-Time": { "type" : "long", "doc_values": true },
+        "offset": { "type" : "long", "doc_values": true }
+      },
+
+      "dynamic_templates": [
+
+        { "acct_io_numbers": {
+            "match_pattern": "regex",
+            "match": "^Acct-(Input|Output)-.*$",
+            "mapping": {
+              "type": "long",
+              "doc_values": true
             }
           }
         },
-        { "no_analyze_strings":{
-            "match":"*",
-            "match_mapping_type":"string",
-            "mapping":{
-              "type":"string",
-              "index":"not_analyzed"
+
+        { "ipv4_address": {
+            "path_match": "*_ip",
+            "mapping": {
+              "type": "ip",
+              "doc_values": true
+            }
+          }
+        },
+
+        { "network_port": {
+            "path_match": "*_port",
+            "mapping": {
+              "type": "integer",
+              "doc_values": true
+            }
+          }
+        },
+
+        { "long_number": {
+            "path_match": "*_long",
+            "mapping": {
+              "type": "integer",
+              "doc_values": true
+            }
+          }
+        },
+
+        { "no_analyze_strings": {
+            "match": "*",
+            "mapping": {
+              "type": "string",
+              "index": "not_analyzed",
+              "doc_values": true
             }
           }
         }
+
       ]
     }
   }
 }'
-
diff --git a/doc/schemas/logstash/radius.conf b/doc/schemas/logstash/radius.conf
deleted file mode 100644 (file)
index a837fa3..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-# logstash configuration to process RADIUS detail files
-#
-# Matthew Newton
-# February 2014
-# 
-# RADIUS "detail" files are textual representations of the RADIUS
-# packets, and are written to disk by e.g. FreeRADIUS. They look
-# something like the following, with the timestamp on the first
-# line then all attributes/values tab-indented.
-#
-#      Tue Mar 10 15:32:24 2015
-#              Packet-Type = Access-Request
-#              User-Name = "test@example.com"
-#              Calling-Station-Id = "01-02-03-04-05-06"
-#              Called-Station-Id = "aa-bb-cc-dd-ee-ff:myssid"
-#              NAS-Port = 10
-#              NAS-IP-Address = 10.9.0.4
-#              NAS-Identifier = "Wireless-Controller-1"
-#              Service-Type = Framed-User
-#              NAS-Port-Type = Wireless-802.11
-#
-# This filter processes the detail file such that each attribute
-# is stored as a separate field in the output document.
-
-
-input {
-  stdin {
-    type => radiusdetail
-  }
-}
-
-
-filter {
-
-    if [type] == "radiusdetail" {
-
-       # join all lines of a record together
-       multiline {
-               pattern => "^[^\t]"
-               negate => true
-               what => "previous"
-       }
-
-       # pull off the timestamp
-       grok {
-               match => [ "message", "^(?<timestamp>[^\n\t]+)[\n\t]" ]
-       }
-
-       # create the timestamp field
-       date {
-               match => [ "timestamp", "EEE MMM dd HH:mm:ss yyyy",
-                                       "EEE MMM  d HH:mm:ss yyyy" ]
-       }
-
-       # split the attributes and values into fields
-       kv {
-               field_split => "\n"
-               source => "message"
-               trim => "\" "
-               trimkey => "\t "
-       }
-    }
-}
-
-output {
-  if [type] == "radiusdetail" {
-    elasticsearch {
-      host => localhost
-      protocol => http
-      cluster => elasticsearch
-      index_type => "detail"
-      index => "radius-%{+YYYY.MM.dd}"
-      flush_size => 1000
-    }
-  }
-}
-
index e9de238..a212b31 100755 (executable)
@@ -192,7 +192,7 @@ fi
 
 if [ x"$dir_arg" != x ]
 then
-       $doit $instcmd $dst &&
+       ([ -d $dst ] || $doit $instcmd $dst) &&
 
        if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
        if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
diff --git a/man/man1/dhcpclient.1 b/man/man1/dhcpclient.1
new file mode 100644 (file)
index 0000000..d6a538e
--- /dev/null
@@ -0,0 +1,71 @@
+.TH DHCPCLIENT 1 "19 September 2016" "" "FreeRADIUS Daemon"
+.SH NAME
+dhcpclient - Send a DHCP request with provided RADIUS attributes and get the output response.
+.SH SYNOPSIS
+.B dhcpclient
+.RB [ \-d
+.IR raddb_directory ]
+.RB [ \-D
+.IR dictionary_directory ]
+.RB [ \-f
+.IR file ]
+.RB [ \-h ]
+.RB [ \-i
+.IR interface ]
+.RB [ \-t
+.IR timeout ]
+.RB [ \-v ]
+.RB [ \-x ]
+\fIserver[:port] {discover|request|decline|release|inform|auto}\fP
+.SH DESCRIPTION
+\fBdhcpclient\fP is a DHCP test client program. It can send arbitrary DHCP
+packets to the FreeRADIUS server running as DHCP server, then shows the reply.
+It can be used to test changes you made in the configuration of the radius server,
+or it can be used to monitor if a radius server is up.
+.PP
+\fBdhcpclient\fP reads radius attribute/value pairs from its standard
+input, or from a file specified on the command line. It then encodes
+these attribute/value pairs using the dictionary, and sends them
+to the local/remote server.
+.PP
+
+.SH OPTIONS
+
+.IP \-d\ \fIraddb_directory\fP
+The directory that contains the user dictionary file. Defaults to
+\fI/etc/raddb\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.
+.IP \-h
+Print usage help information.
+.IP \-i\ \fIinterface\fP
+Select which interface to send/receive at packet level on a raw socket.
+.IP \-t\ \fItimeout\fP
+Wait \fItimeout\fP seconds before deciding that the NAS has not
+responded to a request, and re-sending the packet. This may be a floating
+point number, e.g. 2.2.
+.IP \-v
+Print out program version information.
+.IP \-x
+Print out debugging information.
+.IP server[:port]
+The hostname or IP address of the remote server. Optionally a UDP port
+can be specified. If no UDP port is specified, it is looked up in
+\fI/etc/services\fP. The service name looked for is \fBradacct\fP for
+accounting packets, and \fBradius\fP for all other requests. If a
+service is not found in \fI/etc/services\fP, 1813 and 1812 are used
+respectively.
+.IP discover\ |\ request\ |\ decline\ |\ release\ |\ inform\ |\ auto
+DHCP options - use the type relevant for testing
+
+.SH SEE ALSO
+radiusd(8)
+.SH AUTHORS
+Alan DeKok <aland@freeradius.org>
diff --git a/man/man1/rad_counter.1 b/man/man1/rad_counter.1
new file mode 100644 (file)
index 0000000..1f56e7c
--- /dev/null
@@ -0,0 +1,43 @@
+.TH RAD_COUNTER 1 "19 September 2016" "" "FreeRADIUS Daemon"
+.SH NAME
+rad_counter - Query and maintain FreeRADIUS rlm_counter DB file.
+
+This tool is deprecated
+
+.SH SYNOPSIS
+.B rad_counter
+.RB [ \--file
+.IR counter_filename ]
+.RB [ \--user
+.IR username ]
+.RB [ \--match
+.IR <regex> ]
+.RB [ \--reset 
+.IR number]
+.RB [ \--help ]
+.RB [ \--
+.IR(hours|minutes|seconds) ]
+
+.SH DESCRIPTION
+\fBrad_counter\fP is a tool that can query and maintain FreeRADIUS rlm_counter DB files.
+.PP
+
+.SH OPTIONS
+
+.IP \--file=
+Counter DB filename.
+.IP \--user=\ \fIusername\fP
+Information for specific user.
+.IP \--match=\ \fI<regex>\fP
+Information for matching users.
+.IP \--reset=\ \fInumber\fP
+Reset counter to <number>. If divisor is set use it, else <number> means seconds.
+.IP \--help
+Show the help screen.
+.IP \--(hours\ |\ minutes\ |\ seconds)
+Specify information divisor.
+
+.SH SEE ALSO
+radiusd(8)
+.SH AUTHORS
+Alan DeKok <aland@freeradius.org>
index 68fbee3..f95b3bf 100644 (file)
@@ -10,7 +10,7 @@
 .RE
 .sp
 ..
-.TH unlang 5 "24 November 2014" "" "FreeRADIUS Processing un-language"
+.TH unlang 5 "05 February 2016" "" "FreeRADIUS Processing un-language"
 .SH NAME
 unlang \- FreeRADIUS Processing un\-language
 .SH DESCRIPTION
@@ -40,12 +40,14 @@ one one line.  Each entry begins with a keyword.  Entries are
 organized into lists.  Processing of the language is line by line,
 from the start of the list to the end.  Actions are executed
 per-keyword.
-.IP module-name
+.IP module-name[.section-name]
 A reference to the named module.  When processing reaches this point,
 the pre-compiled module is called.  The module may succeed or fail,
 and will return a status to "unlang" if so.  This status can be tested
 in a condition.  See the "Simple Conditions" text in the CONDITIONS
 section, and MODULE RETURN CODES, below.
+If a section-name is provided, it will cause the module to execute 
+as if it were listed in the named section.
 
 .DS
        chap  # call the CHAP module
@@ -661,7 +663,7 @@ as with %{%{One}:-%{%{Two}:-%{Three}}}
 .PP
 String lengths and arrays
 .RS
-Similar to a Unix shell, there are ways to reference string lenths,
+Similar to a Unix shell, there are ways to reference string lengths,
 and the second or more instance of an attribute in a list.  If you
 need more than this functionality, we suggest using a real language.
 .IP %{strlen:string}
@@ -775,6 +777,12 @@ This operator is valid only for attributes of integer type.
 .IP !*
 Delete all occurances of the named attribute, no matter what the
 value.
+.IP =~
+Keep all attributes having values which match the given regular
+expression.  If no attribute matches, nothing else is done.
+.IP !~
+Keep all attributes having values which fail to match the given
+regular expression.  If no attribute matches, nothing else is done.
 .RE
 .IP Values
 .br
index d48a328..3f8e0eb 100644 (file)
@@ -1,11 +1,16 @@
 FREERADIUS-NOTIFICATION-MIB DEFINITIONS ::= BEGIN
-       IMPORTS freeRadius
+       IMPORTS
+               MODULE-IDENTITY, NOTIFICATION-TYPE
+                       FROM SNMPv2-SMI
+               freeradiusObjects
+                       FROM FREERADIUS-MGMT-MIB
+               freeRadius
                        FROM FREERADIUS-SMI
-               radiusAuthServerAddress,radiusAuthClientServerPortNumber
+               radiusAuthServerAddress,radiusAuthClientServerPortNumber
                        FROM RADIUS-AUTH-CLIENT-MIB
-              radiusAuthServIdent
+               radiusAuthServIdent
                        FROM RADIUS-AUTH-SERVER-MIB
-              radiusd
+               radiusd
                        FROM FREERADIUS-PRODUCT-RADIUSD-MIB;
 
 freeRadiusNotificationMib MODULE-IDENTITY
@@ -29,19 +34,19 @@ freeRadiusNotificationMib MODULE-IDENTITY
 serverGlobal  OBJECT IDENTIFIER ::= { freeRadiusNotificationMib 1 }
 
 serverStart NOTIFICATION-TYPE
-       OBJECTS { identity }
+       OBJECTS { radiusObject }
        STATUS current
        DESCRIPTION "Notification that the server has started"
        ::= { serverGlobal 1 }
 
 serverStop NOTIFICATION-TYPE
-       OBJECTS { identity }
+       OBJECTS { radiusObject }
        STATUS current
        DESCRIPTION "Notification that the server is stopping"
        ::= { serverGlobal 2 }
 
 serverMaxRequests NOTIFICATION-TYPE
-       OBJECTS { identity }
+       OBJECTS { radiusObject }
        STATUS current
        DESCRIPTION "Notification that the server has hit the max_requests limit"
        ::= { serverGlobal 3 }
@@ -49,13 +54,13 @@ serverMaxRequests NOTIFICATION-TYPE
 serverSignal  OBJECT IDENTIFIER ::= { serverGlobal 4 }
 
 signalHup NOTIFICATION-TYPE
-       OBJECTS { identity }
+       OBJECTS { radiusObject }
        STATUS current
        DESCRIPTION "Notification that the server has received a HUP signal"
        ::= { serverSignal 1 }
 
 signalTerm NOTIFICATION-TYPE
-       OBJECTS { identity }
+       OBJECTS { radiusObject }
        STATUS current
        DESCRIPTION "Notification that the server has received a TERM signal"
        ::= { serverSignal 2 }
@@ -63,25 +68,25 @@ signalTerm NOTIFICATION-TYPE
 serverThread  OBJECT IDENTIFIER ::= { serverGlobal 5 }
 
 threadStart NOTIFICATION-TYPE
-       OBJECTS { identity }
+       OBJECTS { radiusObject }
        STATUS current
        DESCRIPTION "Notification that a thread has started"
        ::= { serverThread 1 }
 
 threadStop NOTIFICATION-TYPE
-       OBJECTS { identity }
+       OBJECTS { radiusObject }
        STATUS current
        DESCRIPTION "Notification that a thread has stopped"
        ::= { serverThread 2 }
 
 threadUnresponsive NOTIFICATION-TYPE
-       OBJECTS { identity }
+       OBJECTS { radiusObject }
        STATUS current
        DESCRIPTION "Notification that a child thread is unresponsive"
        ::= { serverThread 3 }
 
 threadMaxThreads NOTIFICATION-TYPE
-       OBJECTS { identity }
+       OBJECTS { radiusObject }
        STATUS current
        DESCRIPTION "Notification that the max_threads limit has been reached"
        ::= { serverThread 4 }
index c76937a..35bf00b 100644 (file)
@@ -16,7 +16,7 @@ radiusStatMIB MODULE-IDENTITY
              "The MIB module for entities implementing the statistics
               side of the Remote Access Dialin User Service (RADIUS)
               authentication protocol."
-       REVISION "0001020000Z"    
+       REVISION "0001020000Z"
        DESCRIPTION "Experimental Version"
        ::= { radiusStatistics 1 }
 
@@ -101,25 +101,25 @@ radiusStatNASTable OBJECT-TYPE
        ::= { radiusStatMIB 7 }
 
 radiusStatNASEntry OBJECT-TYPE
-       SYNTAX     RadiusNASStatEntry
+       SYNTAX     RadiusStatNASEntry
        MAX-ACCESS not-accessible
        STATUS     current
        DESCRIPTION
              "An entry (conceptual row) representing a Network
               Access Server"
-       INDEX      { NASIndex }
+       INDEX      { nasIndex }
        ::= { radiusStatNASTable 1 }
 
 RadiusStatNASEntry ::= SEQUENCE {
-       NASIndex                           Integer32,
-       NASAddress                         IpAddress,
-       NASID                              SnmpAdminString,
-       NASLines                           Counter32,
-       NASLinesInUse                      Counter32,
-       NASLinesIdle                       Counter32,
+       nasIndex                           Integer32,
+       nasAddress                         IpAddress,
+       nasID                              SnmpAdminString,
+       nasLines                           Counter32,
+       nasLinesInUse                      Counter32,
+       nasLinesIdle                       Counter32,
 }
 
-NASIndex OBJECT-TYPE
+nasIndex OBJECT-TYPE
        SYNTAX     Integer32 (1..2147483647)
        MAX-ACCESS not-accessible
        STATUS     current
@@ -127,7 +127,7 @@ NASIndex OBJECT-TYPE
              "A number uniquely identifying each NAS"
        ::= { radiusStatNASEntry 1 }
 
-NASAddress OBJECT-TYPE
+nasAddress OBJECT-TYPE
        SYNTAX     IpAddress
        MAX-ACCESS read-only
        STATUS     current
@@ -135,7 +135,7 @@ NASAddress OBJECT-TYPE
              "The NAS-IP-Address"
        ::= { radiusStatNASEntry 2 }
 
-NASID OBJECT-TYPE
+nasID OBJECT-TYPE
        SYNTAX     SnmpAdminString
        MAX-ACCESS read-only
        STATUS     current
@@ -143,7 +143,7 @@ NASID OBJECT-TYPE
              "The NAS-Identifier"
        ::= { radiusStatNASEntry 3 }
 
-NASLines OBJECT-TYPE
+nasLines OBJECT-TYPE
        SYNTAX Counter32
        MAX-ACCESS read-only
        STATUS current
@@ -151,7 +151,7 @@ NASLines OBJECT-TYPE
              "The number of lines served by the NAS"
        ::= { radiusStatNASEntry 4 }
 
-NASLinesInUse OBJECT-TYPE
+nasLinesInUse OBJECT-TYPE
        SYNTAX Counter32
        MAX-ACCESS read-only
        STATUS current
@@ -159,7 +159,7 @@ NASLinesInUse OBJECT-TYPE
              "The number of lines currently in use on this NAS"
        ::= { radiusStatNASEntry 5 }
 
-NASLinesIdle OBJECT-TYPE
+nasLinesIdle OBJECT-TYPE
        SYNTAX Counter32
        MAX-ACCESS read-only
        STATUS current
@@ -190,10 +190,10 @@ RadiusStatNASPortEntry ::= SEQUENCE {
        radiusStatPortID                              Integer32,
        radiusStatPortFramedAddress                  IpAddress,
        radiusStatPortTotalLogins                     Counter32,
-       radiusStatPortStatus                          Counter32,
+       radiusStatPortStatus                          INTEGER,
        radiusStatPortStatusDate                      SnmpAdminString,
        radiusStatPortUpTime                          TimeTicks,
-       radiusStatPortLastLogin                       SnmpAdminString,
+       radiusStatPortLastLoginName                   SnmpAdminString,
        radiusStatPortLastLoginDate                   SnmpAdminString,
        radiusStatPortLastLogoutDate                  SnmpAdminString,
        radiusStatPortIdleTotalTime                   TimeTicks,
index 590c023..c77a95b 100644 (file)
@@ -348,6 +348,14 @@ 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``.
 
+rlm_preprocess
+~~~~~~~~~~~~~~
+
+In 2.x.x ``huntroups`` and ``users`` files were loaded from default locations
+without being configured explicitly. Since 3.x.x you need to set
+``huntgroups`` and ``users`` configuration item(s) in module section in order
+to get them being processed.
+
 New Modules
 -----------
 
index 25602a8..b087dc1 100644 (file)
@@ -7,7 +7,7 @@ LOCAL_FILES :=          clients.conf dictionary templates.conf experimental.conf \
 DEFAULT_SITES :=       default inner-tunnel
 LOCAL_SITES :=         $(addprefix raddb/sites-enabled/,$(DEFAULT_SITES))
 
-DEFAULT_MODULES :=     always attr_filter cache_eap chap \
+DEFAULT_MODULES :=     always attr_filter cache_eap chap date \
                        detail detail.log digest dhcp dynamic_clients eap \
                        echo exec expiration expr files linelog logintime \
                        mschap ntlm_auth pap passwd preprocess radutmp realm \
index c186ab0..cc12464 100644 (file)
@@ -33,6 +33,9 @@ ca: ca.der
 .PHONY: server
 server: server.pem server.vrfy
 
+.PHONY: verify
+verify: server.vrfy client.vrfy
+
 passwords.mk: server.cnf ca.cnf client.cnf
        @echo "PASSWORD_SERVER  = '$(shell grep output_password server.cnf | sed 's/.*=//;s/^ *//')'"           > $@
        @echo "PASSWORD_CA      = '$(shell grep output_password ca.cnf | sed 's/.*=//;s/^ *//')'"               >> $@
index 624bc09..fe9ddd8 100644 (file)
@@ -98,12 +98,12 @@ cache {
                # <list>:<attribute> <op> <value>
 
                # Cache all instances of Reply-Message in the reply list
-               reply:Reply-Message += &reply:Reply-Message
+               &reply:Reply-Message += &reply:Reply-Message
 
                # Add our own to show when the cache was last updated
-               reply:Reply-Message += "Cache last updated at %t"
+               &reply:Reply-Message += "Cache last updated at %t"
 
-               reply:Class := "%{randstr:ssssssssssssssssssssssssssssssss}"
+               &reply:Class := "%{randstr:ssssssssssssssssssssssssssssssss}"
        }
 
        #  This module supports a number of runtime configuration parameters
index 8759784..0e8d5ca 100644 (file)
@@ -11,9 +11,6 @@
 #  common side effect of setting 'Auth-Type := EAP' is that the
 #  users then cannot use ANY other authentication method.
 #
-#  EAP types NOT listed here may be supported via the "eap2" module.
-#  See experimental.conf for documentation.
-#
 eap {
        #  Invoke the default supported EAP type when
        #  EAP-Identity response is received.
@@ -200,6 +197,15 @@ eap {
                #
                ca_file = ${cadir}/ca.pem
 
+               #  OpenSSL will automatically create certificate chains,
+               #  unless we tell it to not do that.  The problem is that
+               #  it sometimes gets the chains right from a certificate
+               #  signature view, but wrong from the clients view.
+               #
+               #  When setting "auto_chain = no", the server certificate
+               #  file MUST include the full certificate chain.
+       #       auto_chain = yes
+
                #
                #  If OpenSSL supports TLS-PSK, then we can use
                #  a PSK identity and (hex) password.  When the
@@ -228,7 +234,7 @@ eap {
                #  For DH cipher suites to work, you have to
                #  run OpenSSL to create the DH file first:
                #
-               #       openssl dhparam -out certs/dh 1024
+               #       openssl dhparam -out certs/dh 2048
                #
                dh_file = ${certdir}/dh
 
@@ -264,6 +270,7 @@ eap {
                #
        #       include_length = yes
 
+
                #  Check the Certificate Revocation List
                #
                #  1) Copy CA certificates and CRLs to same directory.
@@ -313,8 +320,20 @@ eap {
                # Set this option to specify the allowed
                # TLS cipher suites.  The format is listed
                # in "man 1 ciphers".
+               #
+               # For EAP-FAST, use "ALL:!EXPORT:!eNULL:!SSLv2"
+               #
                cipher_list = "DEFAULT"
 
+               # Work-arounds for OpenSSL nonsense
+               # OpenSSL 1.0.1f and 1.0.1g do not calculate
+               # the EAP keys correctly.  The fix is to upgrade
+               # OpenSSL, or disable TLS 1.2 here. 
+               #
+               #  For EAP-FAST, this MUST be set to "yes".
+               #
+#              disable_tlsv1_2 = no
+
                #
 
                #
@@ -366,16 +385,6 @@ eap {
                        enable = yes
 
                        #
-                       #  Internal "name" of the session cache. Used to distinguish which
-                       #  TLS context sessions belong to.
-                       #
-                       #  The server will generate a random value if unset. This will change
-                       #  across server restart so you MUST set the "name" if you want to
-                       #  persist sessions (see below).
-                       #
-               #       name = "EAP module"
-
-                       #
                        #  Lifetime of the cached entries, in hours. The sessions will be
                        #  deleted/invalidated after this time.
                        #
@@ -391,14 +400,13 @@ eap {
                        max_entries = 255
 
                        #
-                       #  Internal "name" of the session cache.
-                       #  Used to distinguish which TLS context
-                       #  sessions belong to.
+                       #  Internal "name" of the session cache. Used to
+                       #  distinguish which TLS context sessions belong to.
                        #
-                       #  The server will generate a random value
-                       #  if unset. This will change across server
-                       #  restart so you MUST set the "name" if you
-                       #  want to persist sessions (see below).
+                       #  The server will generate a random value if unset.
+                       #  This will change across server restart so you MUST
+                       #  set the "name" if you want to persist sessions (see
+                       #  below).
                        #
                        #name = "EAP module"
 
@@ -428,7 +436,21 @@ eap {
                #  default configuration.  Uncomment it, and configure
                #  the correct paths below to enable it.
                #
+               #  If OCSP checking is enabled, and the OCSP checks fail,
+               #  the verify section is not run.
+               #
+               #  If OCSP checking is disabled, the verify section is
+               #  run on successful certificate validation.
+               #
                verify {
+                       #  If the OCSP checks succeed, the verify section
+                       #  is run to allow additional checks.
+                       #
+                       #  If you want to skip verify on OCSP success,
+                       #  uncomment this configuration item, and set it
+                       #  to "yes".
+       #               skip_if_ocsp_ok = no
+
                        #  A temporary directory where the client
                        #  certificates are stored.  This directory
                        #  MUST be owned by the UID of the server,
@@ -809,4 +831,43 @@ eap {
                #  identify it.
 #              identity = "FreeRADIUS"
        }
+
+       ## EAP-FAST
+       #
+       #  The FAST module implements the EAP-FAST protocol
+       #
+#      fast {
+               # Point to the common TLS configuration
+               #
+               # cipher_list though must include "ADH" for anonymous provisioning.
+               # This is not as straight forward as appending "ADH" alongside
+               # "DEFAULT" as "DEFAULT" contains "!aNULL" so instead it is
+               # recommended "ALL:!EXPORT:!eNULL:!SSLv2" is used
+               #
+#              tls = tls-common
+
+               # PAC lifetime in seconds (default: seven days)
+               #
+#              pac_lifetime = 604800
+
+               # Authority ID of the server
+               #
+               # if you are running a cluster of RADIUS servers, you should make
+               # the value chosen here (and for "pac_opaque_key") the same on all
+               # your RADIUS servers.  This value should be unique to your
+               # installation.  We suggest using a domain name.
+               #
+#              authority_identity = "1234"
+
+               # PAC Opaque encryption key (must be exactly 32 bytes in size)
+               #
+               # This value MUST be secret, and MUST be generated using
+               # a secure method, such as via 'openssl rand -hex 32'
+               #
+#              pac_opaque_key = "0123456789abcdef0123456789ABCDEF"
+
+               # Same as for TTLS, PEAP, etc.
+               #
+#              virtual_server = inner-tunnel
+#      }
 }
index 0a1cf02..4b7e458 100644 (file)
@@ -154,6 +154,10 @@ ldap {
 
                #  Filter for user objects, should be specific enough
                #  to identify a single user object.
+               #
+               #  For Active Directory, you should use
+               #  "samaccountname=" instead of "uid="
+               #
                filter = "(uid=%{%{Stripped-User-Name}:-%{User-Name}})"
 
                #  SASL parameters to use for user binds
index be97d3e..4a59483 100644 (file)
@@ -139,7 +139,11 @@ sql {
        delete_stale_sessions = yes
 
        # Write SQL queries to a logfile. This is potentially useful for tracing
-       # issues with authorization queries.
+       # issues with authorization queries.  See also "logfile" directives in
+       # mods-config/sql/main/*/queries.conf.  You can enable per-section logging
+       # by enabling "logfile" there, or global logging by enabling "logfile" here.
+       #
+       # Per-section logging can be disabled by setting "logfile = ''"
 #      logfile = ${logdir}/sqllog.sql
 
        #  Set the maximum query duration and connection timeout
index 8c601cf..3930fed 100644 (file)
@@ -33,7 +33,7 @@
 #nochap
 #      User-Name =* ANY,
 #      User-Password =* ANY,
-#      NAS-Ip-Address =* ANY,
+#      NAS-IP-Address =* ANY,
 #      NAS-Identifier =* ANY
 
 # The entry for the 'brokenas' realm removes the attribute NAS-Port-Type
@@ -59,4 +59,5 @@ DEFAULT
        State =* ANY,
        NAS-IP-Address =* ANY,
        NAS-Identifier =* ANY,
+       Operator-Name =* ANY,
        Proxy-State =* ANY
index cec4c02..1216e9f 100644 (file)
@@ -75,13 +75,20 @@ use constant {
        RLM_MODULE_NUMCODES => 9  # How many return codes there are
 };
 
-# 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;
+# Same as src/include/log.h
+use constant {
+       L_AUTH         => 2,  # Authentication message
+       L_INFO         => 3,  # Informational message
+       L_ERR          => 4,  # Error message
+       L_WARN         => 5,  # Warning
+       L_PROXY        => 6,  # Proxy messages
+       L_ACCT         => 7,  # Accounting messages
+       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_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
+};
 
 #  Global variables can persist across different calls to the module.
 #
index f892049..80ccc11 100644 (file)
@@ -89,7 +89,8 @@ GO
 CREATE TABLE [radusergroup] (
        [id] [int] IDENTITY (1, 1) NOT NULL ,
        [UserName] [varchar] (64) NOT NULL ,
-       [GroupName] [varchar] (64) NULL
+       [GroupName] [varchar] (64) NULL ,
+       [Priority] [int] NULL
 ) ON [PRIMARY]
 GO
 
index 75611ad..4050802 100644 (file)
@@ -163,14 +163,11 @@ authorize_group_reply_query = "\
 #                      - 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_count_query = "\
+       SELECT COUNT(*) \
+       FROM ${acct_table1} \
+       WHERE username = '%{SQL-User-Name}' \
+       AND acctstoptime IS NULL"
 
 simul_verify_query = "\
        SELECT \
index c5185be..ca5ac77 100644 (file)
@@ -128,7 +128,7 @@ CREATE TABLE radpostauth (
   username varchar(64) NOT NULL default '',
   pass varchar(64) NOT NULL default '',
   reply varchar(32) NOT NULL default '',
-  authdate timestamp NOT NULL,
+  authdate timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
   PRIMARY KEY  (id)
 ) ENGINE = INNODB;
 
index 2df2d3b..387bcf9 100644 (file)
@@ -133,14 +133,11 @@ authorize_group_reply_query = "\
 #                      - 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_count_query = "\
+       SELECT COUNT(*) \
+       FROM ${acct_table1} \
+       WHERE UserName = '%{SQL-User-Name}' \
+       AND AcctStopTime IS NULL"
 
 simul_verify_query = "\
        SELECT \
index 962f4f0..c33581c 100644 (file)
@@ -166,21 +166,18 @@ authorize_group_reply_query = "\
 #                       - 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"
+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
index ae1f8be..b4118c2 100644 (file)
@@ -153,14 +153,11 @@ authorize_group_reply_query = "\
 #                      - 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_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, \
index 5c1ac4b..87d01a5 100644 (file)
@@ -9,7 +9,7 @@
 # Verify rp parameters
 #
 psk_authorize {
-       if (TLS-PSK-Identity) {
+       if (&TLS-PSK-Identity) {
                # TODO: may need to check trust-router-apc as well
                if ("%{psksql:select distinct keyid from authorizations_keys where keyid = '%{tls-psk-identity}' and '%{trust-router-coi}' like coi and '%{gss-acceptor-realm-name}' like acceptor_realm and '%{gss-acceptor-host-name}' like hostname;}") {
                        # do things here
@@ -52,21 +52,21 @@ abfab_client_check {
 #  A policy which is used to validate channel-bindings.
 #
 abfab_channel_bindings {
-       if (GSS-Acceptor-Service-Name && (outer.request:GSS-Acceptor-Service-Name != GSS-Acceptor-Service-Name)) {
+       if (&GSS-Acceptor-Service-Name && (&outer.request:GSS-Acceptor-Service-Name != &GSS-Acceptor-Service-Name)) {
                reject
        }
 
-       if (GSS-Acceptor-Host-Name && outer.request:GSS-Acceptor-Host-Name != GSS-Acceptor-Host-Name ) {
+       if (&GSS-Acceptor-Host-Name && &outer.request:GSS-Acceptor-Host-Name != &GSS-Acceptor-Host-Name ) {
                reject
        }
 
-       if (GSS-Acceptor-Realm-Name && outer.request:GSS-Acceptor-Realm-Name != GSS-Acceptor-Realm-Name ) {
+       if (&GSS-Acceptor-Realm-Name && &outer.request:GSS-Acceptor-Realm-Name != &GSS-Acceptor-Realm-Name ) {
                reject
        }
 
-       if (GSS-Acceptor-Service-Name || GSS-Acceptor-Realm-Name || GSS-Acceptor-Host-Name) {
+       if (&GSS-Acceptor-Service-Name || &GSS-Acceptor-Realm-Name || &GSS-Acceptor-Host-Name) {
                update control {
-                       Chbind-Response-Code := success
+                       &Chbind-Response-Code := success
                }
 
                #
@@ -76,9 +76,9 @@ abfab_channel_bindings {
                #  then they won't be copied to the reply.
                #
                update reply {
-                       GSS-Acceptor-Service-Name = &GSS-Acceptor-Service-Name
-                       GSS-Acceptor-Host-Name = &GSS-Acceptor-Host-Name
-                       GSS-Acceptor-Realm-Name = &GSS-Acceptor-Realm-Name
+                       &GSS-Acceptor-Service-Name = &GSS-Acceptor-Service-Name
+                       &GSS-Acceptor-Host-Name = &GSS-Acceptor-Host-Name
+                       &GSS-Acceptor-Realm-Name = &GSS-Acceptor-Realm-Name
                }
        }
 
index 60edfcf..0e3e450 100644 (file)
@@ -32,7 +32,12 @@ acct_unique {
        #  initial authentication session (Common in a
        #  wireless environment).
        #
-       if ("%{string:Class}" =~ /${policy.class_value_prefix}([0-9a-f]{32})/i) {
+       update request {
+              Tmp-String-9 := "${policy.class_value_prefix}"
+       }
+
+       if (("%{hex:&Class}" =~ /^%{hex:&Tmp-String-9}/) && \
+           ("%{string:&Class}" =~ /^${policy.class_value_prefix}([0-9a-f]{32})/i)) {
                update request {
                        &Acct-Unique-Session-Id := "%{md5:%{1},%{Acct-Session-ID}}"
                }
index 3cc8042..26583f1 100644 (file)
@@ -44,6 +44,15 @@ debug_session_state {
 }
 
 #
+#  Outputs the contents of the proxy-request state list in debugging (-X) mode
+#
+debug_proxy_request {
+       if("%{debug_attr:proxy-request:}" == '') {
+               noop
+       }
+}
+
+#
 #  Outputs the contents of the main lists in debugging (-X) mode
 #
 debug_all {
index 31b12b5..3930451 100644 (file)
@@ -16,80 +16,195 @@ deny_realms {
 #  what constitutes a user name.
 #
 filter_username {
-       if (!&User-Name) {
-               noop
-       }
+       if (&User-Name) {
+               #
+               #  reject mixed case e.g. "UseRNaMe"
+               #
+               #if (&User-Name != "%{tolower:%{User-Name}}") {
+               #       reject
+               #}
 
-       #
-       #  reject mixed case e.g. "UseRNaMe"
-       #
-       #if (&User-Name != "%{tolower:%{User-Name}}") {
-       #       reject
-       #}
+               #
+               #  reject all whitespace
+               #  e.g. "user@ site.com", or "us er", or " user", or "user "
+               #
+               if (&User-Name =~ / /) {
+                       update request {
+                               &Module-Failure-Message += 'Rejected: User-Name contains whitespace'
+                       }
+                       reject
+               }
 
-       #
-       #  reject all whitespace
-       #  e.g. "user@ site.com", or "us er", or " user", or "user "
-       #
-       if (&User-Name =~ / /) {
-               update reply {
-                       &Reply-Message += 'Rejected: Username contains whitespace'
+               #
+               #  reject Multiple @'s
+               #  e.g. "user@site.com@site.com"
+               #
+               if (&User-Name =~ /@[^@]*@/ ) {
+                       update request {
+                               &Module-Failure-Message += 'Rejected: Multiple @ in User-Name'
+                       }
+                       reject
                }
-               reject
-       }
 
-       #
-       #  reject Multiple @'s
-       #  e.g. "user@site.com@site.com"
-       #
-       if (&User-Name =~ /@.*@/ ) {
-               update reply {
-                       &Reply-Message += 'Rejected: Multiple @ in username'
+               #
+               #  reject double dots
+               #  e.g. "user@site..com"
+               #
+               if (&User-Name =~ /\.\./ ) {
+                       update request {
+                               &Module-Failure-Message += 'Rejected: User-Name contains multiple ..s'
+                       }
+                       reject
                }
-               reject
-       }
 
-       #
-       #  reject double dots
-       #  e.g. "user@site..com"
-       #
-       if (&User-Name =~ /\.\./ ) {
-               update reply {
-                       &Reply-Message += 'Rejected: Username contains ..s'
+               #
+               #  must have at least 1 string-dot-string after @
+               #  e.g. "user@site.com"
+               #
+               if ((&User-Name =~ /@/) && (&User-Name !~ /@(.+)\.(.+)$/))  {
+                       update request {
+                               &Module-Failure-Message += 'Rejected: Realm does not have at least one dot separator'
+                       }
+                       reject
                }
-               reject
-       }
 
-       #
-       #  must have at least 1 string-dot-string after @
-       #  e.g. "user@site.com"
-       #
-       if ((&User-Name =~ /@/) && (&User-Name !~ /@(.+)\.(.+)$/))  {
-               update reply {
-                       &Reply-Message += 'Rejected: Realm does not have at least one dot separator'
+               #
+               #  Realm ends with a dot
+               #  e.g. "user@site.com."
+               #
+               if (&User-Name =~ /\.$/)  {
+                       update request {
+                               &Module-Failure-Message += 'Rejected: Realm ends with a dot'
+                       }
+                       reject
+               }
+
+               #
+               #  Realm begins with a dot
+               #  e.g. "user@.site.com"
+               #
+               if (&User-Name =~ /@\./)  {
+                       update request {
+                               &Module-Failure-Message += 'Rejected: Realm begins with a dot'
+                       }
+                       reject
                }
-               reject
        }
+}
+
+#
+#      Filter the User-Password
+#
+#  Some equipment sends passwords with embedded zeros.
+#  This policy filters them out.
+#
+filter_password {
+       if (&User-Password && \
+          (&User-Password != "%{string:User-Password}")) {
+               update request {
+                       &Tmp-String-0 := "%{string:User-Password}"
+                       &User-Password := "%{string:Tmp-String-0}"
+               }
+        }
+}
 
+filter_inner_identity {
        #
-       #  Realm ends with a dot
-       #  e.g. "user@site.com."
+       #  No names, reject.
        #
-       if (&User-Name =~ /\.$/)  {
-               update reply {
-                       &Reply-Message += 'Rejected: Realm ends with a dot'
+       if (!&outer.request:User-Name || !&User-Name) {
+               update request {
+                       Module-Failure-Message = "User-Name is required for tunneled authentication"
                }
                reject
        }
 
        #
-       #  Realm begins with a dot
-       #  e.g. "user@.site.com"
+       #  Do detailed checks only if the inner and outer
+       #  NAIs are different.
+       #
+       #  If the NAIs are the same, it violates user privacy,
+       #  but is allowed.
        #
-       if (&User-Name =~ /@\./)  {
-               update reply {
-                       &Reply-Message += 'Rejected: Realm begins with a dot'
+       if (&outer.request:User-Name != &User-Name) {
+               #
+               #  Get the outer realm.
+               #
+               if (&outer.request:User-Name =~ /@([^@]+)$/) {
+                       update request {
+                               Outer-Realm-Name = "%{1}"
+                       }
+
+                       #
+                       #  When we have an outer realm name, the user portion
+                       #  MUST either be empty, or begin with "anon".
+                       #
+                       #  We don't check for the full "anonymous", because
+                       #  some vendors don't follow the standards.
+                       #
+                       if (&outer.request:User-Name !~ /^(anon|@)/) {
+                               update request {
+                                       Module-Failure-Message = "User-Name is not anonymized"
+                               }
+                               reject
+                       }
                }
-               reject
+
+               #
+               #  There's no outer realm.  The outer NAI is different from the
+               #  inner NAI.  The User-Name MUST be anonymized.
+               #
+               #  Otherwise, you could log in as outer "bob", and inner "doug",
+               #  and we'd have no idea which one was correct.
+               #
+               elsif (&outer.request:User-Name !~ /^anon/) {
+                       update request {
+                               Module-Failure-Message = "User-Name is not anonymized"
+                       }
+                       reject
+               }
+
+               #
+               #  Get the inner realm.
+               #
+               if (&User-Name =~ /@([^@]+)$/) {
+                       update request {
+                               Inner-Realm-Name = "%{1}"
+                       }
+
+                       #
+                       #  Note that we do EQUALITY checks for realm names.
+                       #  There is no simple way to do case insensitive checks
+                       #  on internationalized domain names.  There is no reason
+                       #  to allow outer "anonymous@EXAMPLE.COM" and inner
+                       #  "user@example.com".  The user should enter the same
+                       #  realm for both identities.
+                       #
+                       #  If the inner realm isn't the same as the outer realm,
+                       #  the inner realm MUST be a subdomain of the outer realm.
+                       #
+                       if (&Outer-Realm-Name && \
+                           (&Inner-Realm-Name != &Outer-Realm-Name) && \
+                           (&Inner-Realm-Name !~ /\.%{Outer-Realm-Name}$/)) {
+                               update request {
+                                       Module-Failure-Message = "Inner realm '%{Inner-Realm-Name}' and outer realm '%{Outer-Realm-Name}' are not from the same domain."
+                               }
+                               reject
+                       }
+
+                       #
+                       #  It's OK to have an inner realm and no outer realm.
+                       #
+                       #  That won't work for roaming, but the local RADIUS server
+                       #  can still authenticate the user.
+                       #
+               }
+
+               #
+               #  It's OK to have an outer realm and no inner realm.
+               #
+               #  It will work for roaming, and the local RADIUS server
+               #  can authenticate the user without the realm.
+               #
        }
 }
diff --git a/raddb/policy.d/moonshot-targeted-ids b/raddb/policy.d/moonshot-targeted-ids
new file mode 100644 (file)
index 0000000..e85b291
--- /dev/null
@@ -0,0 +1,73 @@
+#
+#  The following policies generate targeted IDs for ABFAB (Moonshot)
+#
+#  This policy requires that the UUID package is installed on your platform
+#  and that this is called from the inner-tunnel
+#
+#  The following string attributes need to exist in the UKERNA dictionary
+#  Moonshot-Host-TargetedId (138)
+#  Moonshot-Realm-TargetedId (139)
+#  Moonshot-TR-COI-TargetedId (140)
+#
+#  These attributes should also be listed in the attr_filter policies
+#  post-proxy and pre-proxy when you use attribute filtering:
+#       Moonshot-Host-TargetedId =* ANY,
+#       Moonshot-Realm-TargetedId =* ANY,
+#       Moonshot-TR-COI-TargetedId =* ANY,
+#
+#
+#  targeted_id_salt definition
+#  This salt serves the purpose of protecting targeted IDs against
+#  dictionary attacks, therefore should be chosen as a "random"
+#  string and kept secret.
+#
+targeted_id_salt = "changeme"
+#
+#  Moonshot namespaces
+#  These namespaces are used for UUID generation.
+#  They should not be changed by implementors
+#
+moonshot_host_namespace = "a574a04e-b7ff-4850-aa24-a8599c7de1c6"
+moonshot_realm_namespace = "dea5f26d-a013-4444-977d-d09fc990d2e6"
+moonshot_coi_namespace = "145d7e7e-7d54-43ee-bbcb-3c6ad9428247"
+#  This policy generates a host-specific targeted ID
+#
+moonshot_host_tid.post-auth {
+       #  generate a UUID for Moonshot-Host-TargetedId
+       #  targeted id = (uuid -v 5 [namespace] [username][salt][RP host name])@[IdP realm name]
+       if (&outer.request:GSS-Acceptor-Host-Name) {
+               if ("%{echo:/usr/bin/uuid -v 5 ${policy.moonshot_host_namespace} %{tolower:%{User-Name}}${policy.targeted_id_salt}%{tolower:%{outer.request:GSS-Acceptor-Host-Name}}}" =~ /^([^ ]+)([ ]*)$/) {
+                       update outer.session-state {
+                               Moonshot-Host-TargetedId := "%{1}@%{tolower:%{request:Realm}}"
+                       }
+               }
+       }
+}
+#  This policy generates a realm-specific targeted ID
+#
+moonshot_realm_tid.post-auth {
+       #  generate a UUID for Moonshot-Realm-TargetedId
+       #  targeted id = (uuid -v 5 [namespace] [username][salt][RP realm name])@[IdP realm name]
+       if (&outer.request:GSS-Acceptor-Realm-Name) {
+               if ("%{echo:/usr/bin/uuid -v 5 ${policy.moonshot_realm_namespace} %{tolower:%{User-Name}}${policy.targeted_id_salt}%{tolower:%{outer.request:GSS-Acceptor-Realm-Name}}}" =~ /^([^ ]+)([ ]*)$/) {
+                       update outer.session-state {
+                               Moonshot-Realm-TargetedId := "%{1}@%{tolower:%{request:Realm}}"
+                       }
+               }
+       }
+}
+#  This policy generates a COI-specific targeted ID
+#
+moonshot_coi_tid.post-auth {
+       #  generate a UUID for Moonshot-TR-COI-TargetedId
+       #  targeted id = (uuid -v 5 [namespace] [username][salt][RP COI name])@[IdP realm name]
+       if (&outer.request:Trust-Router-COI) {
+               if ("%{echo:/usr/bin/uuid -v 5 ${policy.moonshot_coi_namespace} %{tolower:%{User-Name}}${policy.targeted_id_salt}%{tolower:%{outer.request:Trust-Router-COI}}}" =~ /^([^ ]+)([ ]*)$/) {
+                       update outer.session-state {
+                               Moonshot-TR-COI-TargetedId := "%{1}@%{tolower:%{request:Realm}}"
+                       }
+               }
+       }
+}
index d4e53a9..3ef581e 100644 (file)
@@ -52,6 +52,19 @@ authenticate {
 #  Once we KNOW that the user has been authenticated, there are
 #  additional steps we can take.
 post-auth {
+       #
+       #  For EAP-TTLS and PEAP, add the cached attributes to the reply.
+       #  The "session-state" attributes are automatically cached when
+       #  an Access-Challenge is sent, and automatically retrieved
+       #  when an Access-Request is received.
+       #
+       #  The session-state attributes are automatically deleted after
+       #  an Access-Reject or Access-Accept is sent.
+       #
+       update {
+               &reply: += &session-state:
+       }
+
        #  Create the CUI value and add the attribute to Access-Accept.
        #  Uncomment the line below if *returning* the CUI.
 #      cui
@@ -99,9 +112,9 @@ post-auth {
                # authentication failure And already has an EAP message
                # For non-ABFAB, we insert the failure all the time, but for ABFAB
                # It's more desirable to preserve reply-message when we can
-if &reply:Eap-Message {
+               if (&reply:Eap-Message) {
                        eap
-                       }
+               }
 
                #  Remove reply message if the response contains an EAP-Message
                remove_reply_message_if_eap
index 8b0cb65..69065e1 100644 (file)
@@ -1,5 +1,10 @@
 # This virtual server allows EAP-TLS to reject access requests
-# based on some certificate attributes.
+# based on some attributes of the certificates involved.
+#
+# To use this virtual server, you must enable it in the tls
+# section of mods-enabled/eap as well as adding a link to this
+# file in sites-enabled/.
+#
 #
 # Value-pairs that are available for checking include:
 #
 # passed in to this virtual server.
 #
 #
-# This virtual server is also useful when using EAP-TLS as it is only called
-# once, just before the final Accept is about to be returned from eap, whereas
-# the outer authorize section is called multiple times for each challenge /
-# response. For this reason, here may be a good location to put authentication
-# logging, and modules that check for further authorization, especially if they
+# This virtual server is also useful when using EAP-TLS as it is
+# only called once, just before the final Accept is about to be
+# returned from eap, whereas the outer authorize section is called
+# multiple times for each challenge / response. For this reason,
+# here may be a good location to put authentication logging, and
+# modules that check for further authorization, especially if they
 # hit external services such as sql or ldap.
 
+
 server check-eap-tls {
 
 
@@ -60,7 +67,7 @@ authorize {
        #
        # Check the client certificate common name against the supplied User-Name
        #
-#      if ("host/%{TLS-Client-Cert-Common-Name}" == &User-Name) {
+#      if (&User-Name == "host/%{TLS-Client-Cert-Common-Name}") {
 #              update config {
 #                      &Auth-Type := Accept
 #              }
index e16363f..0834075 100644 (file)
@@ -262,12 +262,22 @@ authorize {
        filter_username
 
        #
+       #  Some broken equipment sends passwords with embedded zeros.
+       #  i.e. the debug output will show
+       #
+       #       User-Password = "password\000\000"
+       #
+       #  This policy will fix it to just be "password".
+       #
+#      filter_password
+
+       #
        #  The preprocess module takes care of sanitizing some bizarre
        #  attributes in the request, and turning them into attributes
        #  which are more standard.
        #
-       #  It takes care of processing the 'raddb/hints' and the
-       #  'raddb/huntgroups' files.
+       #  It takes care of processing the 'raddb/mods-config/preprocess/hints' 
+       #  and the 'raddb/mods-config/preprocess/huntgroups' files.
        preprocess
 
        #  If you intend to use CUI and you require that the Operator-Name
@@ -464,6 +474,11 @@ authenticate {
        }
 
        #
+       #  For old names, too.
+       #
+       mschap
+
+       #
        #  If you have a Cisco SIP server authenticating against
        #  FreeRADIUS, uncomment the following line, and the 'digest'
        #  line in the 'authorize' section.
index 42b358f..2c6f961 100644 (file)
@@ -47,6 +47,21 @@ listen {
 #  need to setup hints for the remote radius server
 authorize {
        #
+       #  Take a User-Name, and perform some checks on it, for spaces and other
+       #  invalid characters.  If the User-Name appears invalid, reject the
+       #  request.
+       #
+       #  See policy.d/filter for the definition of the filter_username policy.
+       #
+       filter_username
+
+       #
+       #  Do checks on outer / inner User-Name, so that users
+       #  can't spoof us by using incompatible identities
+       #
+#      filter_inner_identity
+
+       #
        #  The chap module will set 'Auth-Type := CHAP' if we are
        #  handling a CHAP request and Auth-Type has not already been set
        chap
@@ -207,6 +222,11 @@ authenticate {
        }
 
        #
+       #  For old names, too.
+       #
+       mschap
+
+       #
        #  Pluggable Authentication Modules.
 #      pam
 
@@ -296,6 +316,14 @@ post-auth {
 
 
        #
+       #  Un-comment the following if you want to generate Moonshot (ABFAB) TargetedIds
+       #  IMPORTANT: This requires the UUID package to be installed!
+       #
+#      moonshot_host_tid
+#      moonshot_realm_tid
+#      moonshot_coi_tid
+
+       #
        #  Instead of "use_tunneled_reply", uncomment the
        #  next two "update" blocks.
        #
index 211daab..3c4aea7 100644 (file)
 ######################################################################
 
 #
-#  Sample contents: just do everything that the default configuration does.
-#
-#  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,
-#  and vice-versa.
+#  You will want to edit this to your local needs.  We suggest copying
+#  the text from the "default" file here, and then editing the text.
+#  That way, any changes to the "default" file will not affect this
+#  virtual server, and vice-versa.
 #
 #  When this virtual server receives the request, the original
 #  attributes can be accessed as "outer.request", "outer.control", etc.
 #  See "man unlang" for more details.
 #
 server virtual.example.com {
-$INCLUDE       ${confdir}/sites-available/default
+authorize {
+       # insert policies here
+}
+
+authenticate {
+       # insert policies here
+}
+
+# etc.
 }
index dff41b1..7a2cf82 100644 (file)
@@ -9,13 +9,11 @@
 # experimental modules
 %bcond_with rlm_idn
 %bcond_with rlm_ruby
-%bcond_with rlm_sql_freetds
 %bcond_with rlm_sql_oracle
 %{?_with_rlm_idn: %global _with_experimental_modules --with-experimental-modules}
 %{?_with_rlm_opendirectory: %global _with_experimental_modules --with-experimental-modules}
 %{?_with_rlm_ruby: %global _with_experimental_modules --with-experimental-modules}
 %{?_with_rlm_securid: %global _with_experimental_modules --with-experimental-modules}
-%{?_with_rlm_sql_freetds: %global _with_experimental_modules --with-experimental-modules}
 %{?_with_rlm_sql_oracle: %global _with_experimental_modules --with-experimental-modules}
 
 %if %{?_with_experimental_modules:1}%{!?_with_experimental_modules:0}
 %{!?_with_rlm_opendirectory: %global _without_rlm_opendirectory --without-rlm_opendirectory}
 %{!?_with_rlm_ruby: %global _without_rlm_ruby --without-rlm_ruby}
 %{!?_with_rlm_securid: %global _without_rlm_securid --without-rlm_securid}
-%{!?_with_rlm_sql_freetds: %global _without_rlm_sql_freetds --without-rlm_sql_freetds}
 %{!?_with_rlm_sql_oracle: %global _without_rlm_sql_oracle --without-rlm_sql_oracle}
 %endif
 
 Summary: High-performance and highly configurable free RADIUS server
 Name: freeradius
-Version: 3.0.10
+Version: 3.0.12
 Release: 2%{?dist}
 License: GPLv2+ and LGPLv2+
 Group: System Environment/Daemons
@@ -224,7 +221,6 @@ BuildRequires: unixODBC-devel
 %description unixODBC
 This plugin provides unixODBC support for the FreeRADIUS server project.
 
-%if %{?_with_rlm_sql_freetds:1}%{!?_with_rlm_sql_freetds:0}
 %package freetds
 Summary: FreeTDS support for FreeRADIUS
 Group: System Environment/Daemons
@@ -234,7 +230,6 @@ BuildRequires: freetds-devel
 
 %description freetds
 This plugin provides FreeTDS support for the FreeRADIUS server project.
-%endif
 
 %if %{?_with_rlm_sql_oracle:1}%{!?_with_rlm_sql_oracle:0}
 %package oracle
@@ -309,12 +304,17 @@ find $RPM_BUILD_DIR/freeradius-server-%{version} \( -name '*.c' -o -name '*.h' \
 
 
 %build
-%ifarch s390 s390x
-export CFLAGS="$RPM_OPT_FLAGS -fPIC"
-%else
-export CFLAGS="$RPM_OPT_FLAGS -fpic"
+# Retain CFLAGS from the environment...
+%if %{?_with_developer:1}%{!?_with_developer:0}
+export CFLAGS="$CFLAGS -fpic"
+export CXXFLAGS="$CFLAGS"
 %endif
 
+# Need to pass these explicitly for clang, else rpmbuilder bails when trying to extract debug info from
+# the libraries.  Guessing GCC does this by default.  Why use clang over gcc? The version of clang
+# which ships with RHEL 6 has basic C11 support, gcc doesn't.
+export LDFLAGS="-Wl,--build-id"
+
 %configure \
         --libdir=%{_libdir}/freeradius \
         --with-system-libtool \
@@ -352,8 +352,6 @@ export CFLAGS="$RPM_OPT_FLAGS -fpic"
         %{?_without_rlm_opendirectory} \
         %{?_with_rlm_securid} \
         %{?_without_rlm_securid} \
-        %{?_with_rlm_sql_freetds} \
-        %{?_without_rlm_sql_freetds} \
         %{?_with_rlm_ruby} \
         %{?_without_rlm_ruby} \
         %{?_with_rlm_cache_memcached} \
@@ -406,9 +404,6 @@ rm -f $RPM_BUILD_ROOT/%{_sysconfdir}/raddb/mods-available/idn
 %if %{?_with_rlm_ruby:0}%{!?_with_rlm_ruby:1}
 rm -rf $RPM_BUILD_ROOT/%{_sysconfdir}/raddb/mods-config/ruby
 %endif
-%if %{?_with_rlm_sql_freetds:0}%{!?_with_rlm_sql_freetds:1}
-rm -rf $RPM_BUILD_ROOT/%{_sysconfdir}/raddb/mods-config/sql/main/mssql
-%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
@@ -567,6 +562,7 @@ fi
 %{_libdir}/freeradius/rlm_digest.so
 %{_libdir}/freeradius/rlm_dynamic_clients.so
 %{_libdir}/freeradius/rlm_eap.so
+%{_libdir}/freeradius/rlm_eap_fast.so
 %{_libdir}/freeradius/rlm_eap_gtc.so
 %{_libdir}/freeradius/rlm_eap_leap.so
 %{_libdir}/freeradius/rlm_eap_md5.so
@@ -594,7 +590,6 @@ fi
 %{_libdir}/freeradius/rlm_soh.so
 %{_libdir}/freeradius/rlm_sometimes.so
 %{_libdir}/freeradius/rlm_sql.so
-%{_libdir}/freeradius/rlm_sqlhpwippool.so
 %{_libdir}/freeradius/rlm_sql_null.so
 %{_libdir}/freeradius/rlm_sql_sqlite.so
 %{_libdir}/freeradius/rlm_sqlcounter.so
@@ -697,10 +692,8 @@ fi
 %attr(640,root,radiusd) %config(noreplace) /etc/raddb/mods-config/ruby/*
 %endif
 # freetds
-%if %{?_with_rlm_sql_freetds:1}%{!?_with_rlm_sql_freetds:0}
 %dir %attr(750,root,radiusd) /etc/raddb/mods-config/sql/main/mssql
 %attr(640,root,radiusd) %config(noreplace) /etc/raddb/mods-config/sql/main/mssql/*
-%endif
 # oracle
 %if %{?_with_rlm_sql_oracle:1}%{!?_with_rlm_sql_oracle:0}
 %dir %attr(750,root,radiusd) /etc/raddb/mods-config/sql
@@ -719,7 +712,9 @@ fi
 %defattr(-,root,root)
 /usr/bin/*
 # man-pages
+%doc %{_mandir}/man1/dhcpclient.1.gz
 %doc %{_mandir}/man1/radclient.1.gz
+%doc %{_mandir}/man1/radcounter.1.gz
 %doc %{_mandir}/man1/radeapclient.1.gz
 %doc %{_mandir}/man1/radlast.1.gz
 %doc %{_mandir}/man1/radtest.1.gz
@@ -781,11 +776,9 @@ fi
 %{_libdir}/freeradius/rlm_ruby.so
 %endif
 
-%if %{?_with_rlm_sql_freetds:1}%{!?_with_rlm_sql_freetds:0}
 %files freetds
 %defattr(-,root,root)
 %{_libdir}/freeradius/rlm_sql_freetds.so
-%endif
 
 %if %{?_with_rlm_sql_oracle:1}%{!?_with_rlm_sql_oracle:0}
 %files oracle
@@ -801,5 +794,5 @@ fi
 
 
 %changelog
-* Wed Sep 22 2013 Alan DeKok <aland@freeradius.org> - 3.0.0
+* Wed Sep 25 2013 Alan DeKok <aland@freeradius.org> - 3.0.0
 - upgrade to latest upstream release
index 5d3c0ca..bccec5e 100644 (file)
@@ -128,7 +128,7 @@ endef
 #
 ifeq "${CPP_MAKEDEPEND}" "yes"
 define ADD_OBJECT_RULE
-$${BUILD_DIR}/objs/%.${OBJ_EXT} $${BUILD_DIR}/objs/%.d: ${1} ${JLIBTOOL}
+$${BUILD_DIR}/objs/%.${OBJ_EXT} $${BUILD_DIR}/objs/%.d: ${1} | ${BOOTSTRAP_BUILD}
        ${2}
        $${CPP} $${CPPFLAGS} $$(addprefix -I,$${SRC_INCDIRS}) $${SRC_DEFS} $$< | sed \
          -n 's,^\# *[0-9][0-9]* *"\([^"]*\)".*,$$@: \1,p' > $${BUILD_DIR}/objs/$$*.d
@@ -137,14 +137,14 @@ endef
 
 else
 define ADD_OBJECT_RULE
-$${BUILD_DIR}/objs/%.${OBJ_EXT} $${BUILD_DIR}/objs/%.d: ${1} ${JLIBTOOL}
+$${BUILD_DIR}/objs/%.${OBJ_EXT} $${BUILD_DIR}/objs/%.d: ${1} | ${BOOTSTRAP_BUILD}
        ${2}
 ${FILTER_DEPENDS}
 endef
 endif
 
 define ADD_ANALYZE_RULE
-$${BUILD_DIR}/plist/%.plist: ${1} ${JLIBTOOL}
+$${BUILD_DIR}/plist/%.plist: ${1}
        ${2}
 endef
 
@@ -589,8 +589,13 @@ else
     BUILD_DIR := $(call CANONICAL_PATH,${BUILD_DIR})
 endif
 
+.PHONY: $(BUILD_DIR)
+$(BUILD_DIR):
+       @mkdir -p $@
+
 # Define compilers and linkers
 #
+BOOTSTRAP_BUILD = 
 COMPILE.c = ${CC}
 COMPILE.cxx = ${CXX}
 CPP = cc -E
@@ -647,6 +652,11 @@ ifneq "$(MAKECMDGOALS)" "clean"
       $(eval -include ${${TGT}_DEPS}))
 endif
 
+# Build rules for installation subdirectories
+$(foreach D,$(patsubst %/,%,$(sort $(dir ${ALL_INSTALL}))),\
+  $(eval $(call ADD_INSTALL_RULE.dir,${D})))
+
+
 scan: ${ALL_PLISTS}
 
 .PHONY: clean.scan
diff --git a/scripts/collectd/radsniff_types.db b/scripts/collectd/radsniff_types.db
new file mode 100644 (file)
index 0000000..8f4fc57
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Collectd type definitions for radsniff probes
+#
+# $Id$
+#
+# Copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+#
+radius_count            received:GAUGE:0:U, linked:GAUGE:0:U, unlinked:GAUGE:0:U, reused:GAUGE:0:U
+radius_latency          smoothed:GAUGE:0:U, avg:GAUGE:0:U, high:GAUGE:0:U, low:GAUGE:0:U
+radius_rtx              none:GAUGE:0:U, 1:GAUGE:0:U, 2:GAUGE:0:U, 3:GAUGE:0:U, 4:GAUGE:0:U, more:GAUGE:0:U, lost:GAUGE:0:U
index 9c0bfe6..9164115 100644 (file)
@@ -46,9 +46,8 @@ define ADD_INSTALL_RULE.exe
     install: $${${1}_INSTALLDIR}/$(notdir ${1})
 
     # Install executable ${1}
-    $${${1}_INSTALLDIR}/$(notdir ${1}): $${${1}_BUILD}/${1}
+    $${${1}_INSTALLDIR}/$(notdir ${1}): ${JLIBTOOL} $${${1}_BUILD}/${1} | $${${1}_INSTALLDIR}
        @$(ECHO) INSTALL ${1}
-       $(Q)$${PROGRAM_INSTALL} -d -m 755 $${${1}_INSTALLDIR}
        $(Q)$${PROGRAM_INSTALL} -c -m 755 $${BUILD_DIR}/bin/${1} $${${1}_INSTALLDIR}/
        $(Q)$${${1}_POSTINSTALL}
 
@@ -66,9 +65,8 @@ define ADD_INSTALL_RULE.a
     install: $${${1}_INSTALLDIR}/$(notdir ${1})
 
     # Install static library ${1}
-    $${${1}_INSTALLDIR}/$(notdir ${1}): ${1}
+    $${${1}_INSTALLDIR}/$(notdir ${1}): ${JLIBTOOL} ${1} | $${${1}_INSTALLDIR}
        @$(ECHO) INSTALL ${1}
-       $(Q)$${PROGRAM_INSTALL} -d -m 755 $${${1}_INSTALLDIR}
        $(Q)$${PROGRAM_INSTALL} -c -m 755 $${BUILD_DIR}/lib/${1} $${${1}_INSTALLDIR}/
        $(Q)$${${1}_POSTINSTALL}
 
@@ -89,10 +87,9 @@ define ADD_INSTALL_RULE.la
     install: $${${1}_INSTALLDIR}/$(notdir ${1})
 
     # Install libtool library ${1}
-    $${${1}_INSTALLDIR}/$(notdir ${1}): $${${1}_BUILD}/${1}
+    $${${1}_INSTALLDIR}/$(notdir ${1}): ${JLIBTOOL} $${${1}_BUILD}/${1} | $${${1}_INSTALLDIR}
        @$(ECHO) INSTALL ${1}
-       $(Q)$${PROGRAM_INSTALL} -d -m 755 $${${1}_INSTALLDIR}
-       $(Q)$${PROGRAM_INSTALL} -c -m 755 $${RELINK_FLAGS_MIN} $${BUILD_DIR}/lib/${1} $${${1}_INSTALLDIR}/
+       $(Q)$${PROGRAM_INSTALL} -c -m 755 $${LOCAL_FLAGS_MIN} $${BUILD_DIR}/lib/${1} $${${1}_INSTALLDIR}/
        $(Q)$${${1}_POSTINSTALL}
 
 endef
@@ -110,14 +107,27 @@ define ADD_INSTALL_RULE.man
     install: ${2}/$(notdir ${1})
 
     # Install manual page ${1}
-    ${2}/$(notdir ${1}): ${1}
+    ${2}/$(notdir ${1}): ${JLIBTOOL} ${1} | ${2}
        @$(ECHO) INSTALL $(notdir ${1})
-       $(Q)[ -d ${2} ] || $${PROGRAM_INSTALL} -d -m 755 ${2}
        $(Q)$${PROGRAM_INSTALL} -c -m 644 ${1} ${2}/
 
 endef
 
 
+# ADD_INSTALL_RULE.dir - Parameterized "function" that adds a new rule
+#   and phony target for installing a directory
+#
+#   USE WITH EVAL
+#
+define ADD_INSTALL_RULE.dir
+    # Install directory
+    .PHONY: ${1}
+    ${1}: ${JLIBTOOL}
+       @$(ECHO) INSTALL -d -m 755 ${1}
+       $(Q)$${PROGRAM_INSTALL} -d -m 755 ${1}
+endef
+
+
 # ADD_INSTALL_TARGET - Parameterized "function" that adds a new rule
 #   which installs everything for the target.
 #
index ce1d34e..c04390d 100644 (file)
@@ -79,7 +79,7 @@
 #  define LD_LIBRARY_PATH_LOCAL                "DYLD_FALLBACK_LIBRARY_PATH"
 #endif
 
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || (defined(__sun) && defined(__GNUC__))
 #  define SHELL_CMD                    "/bin/sh"
 #  define DYNAMIC_LIB_EXT              "so"
 #  define MODULE_LIB_EXT               "so"
 #  define SHARED_OPTS                  "-shared"
 #  define MODULE_OPTS                  "-shared"
 #  define LINKER_FLAG_PREFIX           "-Wl,"
+#if !defined(__sun)
 #  define DYNAMIC_LINK_OPTS            LINKER_FLAG_PREFIX "-export-dynamic"
+#else
+#  define DYNAMIC_LINK_OPTS            ""
+#endif
 #  define ADD_MINUS_L
 #  define LD_RUN_PATH                  "LD_RUN_PATH"
 #  define LD_LIBRARY_PATH              "LD_LIBRARY_PATH"
 #  define LD_LIBRARY_PATH_LOCAL                LD_LIBRARY_PATH
 #endif
 
-#if defined(__sun)
+#if defined(__sun) && !defined(__GNUC__)
 #  define SHELL_CMD                    "/bin/sh"
 #  define DYNAMIC_LIB_EXT              "so"
 #  define MODULE_LIB_EXT               "so"
@@ -2228,21 +2232,25 @@ static int run_mode(command_t *cmd)
 
                strcpy(libpath, cmd->arglist->vals[0]);
                add_dotlibs(libpath);
-       l = strrchr(libpath, '/');
-       if (!l) l = strrchr(libpath, '\\');
-       if (l) {
-               *l = '\0';
-               l = libpath;
-       } else {
-               l = ".libs/";
-       }
+               l = strrchr(libpath, '/');
+               if (!l) l = strrchr(libpath, '\\');
+               if (l) {
+                       *l = '\0';
+                       l = libpath;
+               } else {
+                       l = ".libs/";
+               }
 
-       l = "./build/lib/.libs";
-       setenv(LD_LIBRARY_PATH_LOCAL, l, 1);
-       rv = run_command(cmd, cmd->arglist);
+               l = "./build/lib/.libs";
+               setenv(LD_LIBRARY_PATH_LOCAL, l, 1);
+#ifdef __APPLE__
+               setenv("DYLD_FALLBACK_LIBRARY_PATH", l, 1);
+#endif
+               setenv("FR_LIBRARY_PATH", "./build/lib/local/.libs", 1);
+               rv = run_command(cmd, cmd->arglist);
                if (rv) goto finish;
        }
-         break;
+               break;
 
        default:
                break;
index a95dc30..57915e1 100644 (file)
@@ -98,7 +98,7 @@ define ADD_TARGET_RULE.la
            @$(ECHO) LINK $${${1}_BUILD}/${1}
            $(Q)$${${1}_LINKER} -o $${${1}_BUILD}/${1} $${RPATH_FLAGS} $${LDFLAGS} \
                 $${${1}_LDFLAGS} $${${1}_OBJS} $${LDLIBS} $${${1}_LDLIBS} \
-               $${${1}_PRLIBS}
+                $${${1}_PRLIBS}
            $(Q)$${${1}_POSTMAKE}
 
     ifneq "${ANALYZE.c}" ""
@@ -106,36 +106,37 @@ define ADD_TARGET_RULE.la
     endif
 endef
 
-# ADD_RELINK_RULE.exe - Parametric "function" that adds a rule to relink
-#   the target before installation, so that the paths are correct.
+# ADD_LOCAL_RULE.exe - Parametric "function" that adds a rule to build
+#   a local version of the target.
 #
 #   USE WITH EVAL
 #
-define ADD_RELINK_RULE.exe
-    ${1}: $${${1}_BUILD}/$${RELINK}${1}
+define ADD_LOCAL_RULE.exe
+    ${1}: $${${1}_BUILD}/$${LOCAL}${1}
 
     # used to fix up RPATH for ${1} on install.
-    $${${1}_BUILD}/$${${1}_RELINK}: $${${1}_OBJS} $${${1}_PRBIN} $${${1}_R_PRLIBS}
-           $(Q)$(strip mkdir -p $${${1}_BUILD}/${RELINK}/)
-           $(Q)$${${1}_LINKER} -o $${${1}_BUILD}/$${RELINK}${1} $${RELINK_FLAGS} $${LDFLAGS} \
-                $${${1}_LDFLAGS} $${${1}_OBJS} $${${1}_R_PRLIBS} \
+    $${${1}_BUILD}/$${${1}_LOCAL}: $${${1}_OBJS} $${${1}_PRBIN} $${${1}_LOCAL_PRLIBS}
+           $(Q)$(strip mkdir -p $${${1}_BUILD}/${LOCAL}/)
+           $(Q)$${${1}_LINKER} -o $${${1}_BUILD}/$${LOCAL}${1} $${LOCAL_FLAGS} $${LDFLAGS} \
+                $${${1}_LDFLAGS} $${${1}_OBJS} $${${1}_LOCAL_PRLIBS} \
                 $${LDLIBS} $${${1}_LDLIBS}
            $(Q)$${${1}_POSTMAKE}
 endef
 
-# ADD_RELINK_RULE.la - Parametric "function" that adds a rule to relink
-#   the target before installation, so that the paths are correct.
+# ADD_LOCAL_RULE.la - Parametric "function" that adds a rule to build
+#   a local version of the target.
 #
 #   USE WITH EVAL
 #
-define ADD_RELINK_RULE.la
-    ${1}: $${${1}_BUILD}/$${RELINK}${1}
+define ADD_LOCAL_RULE.la
+    ${1}: $${${1}_BUILD}/$${LOCAL}${1}
 
     # used to fix up RPATH for ${1} on install.
-    $${${1}_BUILD}/$${${1}_RELINK}: $${${1}_OBJS} $${${1}_PRLIBS}
-           $(Q)$(strip mkdir -p $${${1}_BUILD}/${RELINK}/)
-           $(Q)$${${1}_LINKER} -o $${${1}_BUILD}/$${RELINK}${1} $${RELINK_FLAGS} $${LDFLAGS} \
-                $${${1}_LDFLAGS} $${${1}_OBJS} $${LDLIBS} $${${1}_LDLIBS}
+    $${${1}_BUILD}/$${${1}_LOCAL}: $${${1}_OBJS} $${${1}_LOCAL_PRLIBS}
+           $(Q)$(strip mkdir -p $${${1}_BUILD}/${LOCAL}/)
+           $(Q)$${${1}_LINKER} -o $${${1}_BUILD}/$${LOCAL}${1} $${LOCAL_FLAGS} $${LDFLAGS} \
+                $${${1}_LDFLAGS} $${${1}_OBJS} $${LDLIBS} $${${1}_LDLIBS} \
+                $${${1}_LOCAL_PRLIBS}
            $(Q)$${${1}_POSTMAKE}
 
 endef
@@ -155,20 +156,20 @@ endif
 
 # Check if we build shared libraries.
 ifeq "${bm_shared_libs}" "yes"
-    RELINK := local/
+    LOCAL := local/
 
     # RPATH  : flags use to build executables that are installed,
     #          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
+    LOCAL_FLAGS := -rpath $(abspath ${BUILD_DIR})/lib/${LOCAL}/.libs
 
-    RELINK_FLAGS_MIN := -rpath ${libdir}
+    LOCAL_FLAGS_MIN := -rpath ${libdir}
 
     ifneq "${bm_static_libs}" "yes"
         RPATH_FLAGS += --shared
-        RELINK_FLAGS += --shared
+        LOCAL_FLAGS += --shared
     endif
 else
     ifneq "${bm_static_libs}" "yes"
@@ -193,8 +194,8 @@ define ADD_LIBTOOL_SUFFIX
         $${TGT}_NOLIBTOOL := $${TGT_NOLIBTOOL}
     endif
 
-    ifneq "$${RELINK_FLAGS}" ""
-        $${TGT}_RELINK := ${RELINK}$${TGT}
+    ifneq "$${LOCAL_FLAGS}" ""
+        $${TGT}_LOCAL := ${LOCAL}$${TGT}
     endif
 
     # re-write all of the dependencies to have the libtool endings.
@@ -217,14 +218,14 @@ define ADD_LIBTOOL_TARGET
     endif
 
     # If we need to relink, add the relink targets now.
-    ifneq "$${$${TGT}_RELINK}" ""
+    ifneq "$${$${TGT}_LOCAL}" ""
         # add rules to relink the target
 
-        $${TGT}_R_PRLIBS := $$(subst /lib/,/lib/${RELINK},$${$${TGT}_PRLIBS})
+        $${TGT}_LOCAL_PRLIBS := $$(subst $${BUILD_DIR}/lib/,$${BUILD_DIR}/lib/${LOCAL},$${$${TGT}_PRLIBS})
 
-        $$(eval $$(call ADD_RELINK_RULE$${$${TGT}_SUFFIX},$${TGT}))
+        $$(eval $$(call ADD_LOCAL_RULE$${$${TGT}_SUFFIX},$${TGT}))
 
-        $$(eval $$(call ADD_CLEAN_RULE,$${$${TGT}_RELINK}_libtool))
+        $$(eval $$(call ADD_CLEAN_RULE,$${$${TGT}_LOCAL}_libtool))
 
        ifneq "$${$${TGT}_NOLIBTOOL}" ""
             $$(eval $$(call ADD_CLEAN_RULE,$${$${TGT}_NOLIBTOOL}_libtool))
index 96433d6..65f96cf 100644 (file)
@@ -5,7 +5,7 @@
 #
 
 #
-#  Totalmem limit should be lowered to 200.0 if none of the 
+#  Totalmem limit should be lowered to 200.0 if none of the
 #  interpreted language modules or rlm_cache are being used.
 #
 check process radiusd with pidfile /var/run/radiusd/radiusd.pid
diff --git a/scripts/munin/radsniff b/scripts/munin/radsniff
new file mode 100755 (executable)
index 0000000..ae78945
--- /dev/null
@@ -0,0 +1,246 @@
+#!/bin/sh
+: << =cut
+
+=head1 NAME
+
+radsniff - A plugin to consume statistics generated by radsniff via collectd RRD files
+
+=head1 APPLICABLE SYSTEMS
+
+radsniff 3.1.x or later
+
+=head1 CONFIGURATION
+
+This plugin uses the following configuration variables:
+
+ [radsniff]
+  env.host       - The host collectd thinks the radsniff data
+                   originated from (defaults to current host).
+  env.rrd_path   - Path to the directory containing rrd files.
+  env.type       - Either radius_rtx, radius_latency or radius_count
+  env.pkt_type   - The type of packet to graph.
+  env.instance   - radsniff instance name (passed to radsniff with -N).
+
+=head1 AUTHOR
+
+Copyright (C) 2014 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+
+=head1 LICENSE
+
+ 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
+
+=head1 MAGIC MARKERS
+
+ #%# family=manual
+
+=cut
+
+if [ -z "$type" ]; then
+    echo "env.type must be set" >&2
+    exit -1
+fi
+
+if [ -z "$pkt_type" ]; then
+    echo "env.pkt_type must be set" >&2
+    exit -1
+fi
+
+if [ "$1" = "config" ]; then
+    pretty_pkt_type=`echo "$pkt_type" | sed -e 's/_/ /g' | sed 's/^./\U&\E/'`
+
+    case "$type" in
+        radius_rtx)
+            echo "graph_title ${pretty_pkt_type} rtx"
+            echo 'graph_args --base 1000 -l 0 '
+            echo 'graph_period second'
+            echo 'graph_vlabel Exchanged / ${graph_period}'
+            echo 'graph_category RADIUS'
+
+            echo 'none.label no loss'
+            echo 'none.info Responses received after first request'
+            echo 'none.type GAUGE'
+            echo 'none.min 0'
+
+            echo 'one.label 1'
+            echo 'one.info Responses received after one retransmission'
+            echo 'one.type GAUGE'
+            echo 'one.min 0'
+
+            echo 'two.label 2'
+            echo 'two.info Responses received after two retransmissions'
+            echo 'two.type GAUGE'
+            echo 'two.min 0'
+
+            echo 'three.label 3'
+            echo 'three.info Responses received after three retransmissions'
+            echo 'three.type GAUGE'
+            echo 'three.min 0'
+
+            echo 'four.label 4'
+            echo 'four.info Responses received after four retransmissions'
+            echo 'four.type GAUGE'
+            echo 'four.min 0'
+
+            echo 'more.label more'
+            echo 'more.info Responses received after more than four retransmissions'
+            echo 'more.type GAUGE'
+            echo 'more.min 0'
+
+            echo 'lost.label lost'
+            echo 'lost.info Requests to which no response was seen'
+            echo 'lost.type GAUGE'
+            echo 'lost.min 0'
+            ;;
+
+        radius_latency)
+            echo "graph_title ${pretty_pkt_type} latency"
+            echo 'graph_args --base 1000 -l 0 '
+            echo 'graph_vlabel Latency (ms)'
+            echo 'graph_category RADIUS'
+
+            echo 'smoothed.label smoothed avg'
+            echo 'smoothed.info Smoothed average'
+            echo 'smoothed.type GAUGE'
+            echo 'smoothed.min 0'
+
+            echo 'avg.label avg'
+            echo 'avg.info Average latency over the stats interval'
+            echo 'avg.type GAUGE'
+            echo 'avg.min 0'
+
+            echo 'high.label high'
+            echo 'high.info Highest latency over the stats interval'
+            echo 'high.type GAUGE'
+            echo 'high.min 0'
+
+            echo 'low.label low'
+            echo 'low.info Lowest latency over the stats interval'
+            echo 'low.type GAUGE'
+            echo 'low.min 0'
+            ;;
+
+        radius_count)
+            echo "graph_title $pretty_pkt_type counters"
+            echo 'graph_args --base 1000 -l 0 '
+            echo 'graph_period second'
+            echo 'graph_vlabel Packets / ${graph_period}'
+            echo 'graph_category RADIUS'
+
+            echo 'received.label received'
+            echo 'received.info Packets of this type received'
+            echo 'received.type GAUGE'
+            echo 'received.min 0'
+
+            echo 'linked.label linked'
+            echo 'linked.info Packets linked to another request or response'
+            echo 'linked.type GAUGE'
+            echo 'linked.min 0'
+
+            echo 'unlinked.label unlinked'
+            echo 'unlinked.info Packets not linked to another request or response'
+            echo 'unlinked.type GAUGE'
+            echo 'unlinked.min 0'
+
+            echo 'reused.label reused'
+            echo 'reused.info Request which (prematurely) re-used the same ID as a previous request'
+            echo 'reused.type GAUGE'
+            echo 'reused.min 0'
+            ;;
+        *)
+            echo "env.type ($type) is invalid must be radius_rtx, radius_latency, or radius_count" >&2
+            exit -1
+    esac
+    exit 0
+fi
+
+HOST=${host:-`hostname -f`}
+INSTANCE=${instance:-'radsniff'}
+RRD_PATH=${rrd_path:-"/var/lib/collectd/rrd/${HOST}/${INSTANCE}-exchanged"}
+RRD_PATH="${RRD_PATH}/${type}-${pkt_type}.rrd"
+RRD_RES=${rrd_res:-300}
+
+if [ ! -e "$RRD_PATH" ]; then
+    echo "rrd file '$RRD_PATH' does not exist" >&2
+    exit -1
+fi
+
+fetch_data()
+{
+    # RRD tool doesn't always select the correct period (seems
+    # to round up and give us -nan results) in the interest of
+    # gap free graphing, we attempt to get the last two periods
+    # worth of data, and then use the newest non -nan one.
+    # It's not perfect and should be fixed at some point...
+    rrd_last=`rrdtool fetch "$RRD_PATH" $1 -r $RRD_RES -e $(expr $(date +%s) / $RRD_RES \* $RRD_RES) -s end-$(expr $RRD_RES \* 2)`; ret=$?
+    if [ $ret -ne 0 ]; then
+        echo "$rrd_last" >&2
+        exit $ret
+    fi
+    echo "$rrd_last" | head -1
+    echo "$rrd_last" | grep '^[0-9]*:' | grep -v -E '^[0-9]*:( -nan)*$' | tail -1
+}
+
+fetch_data_column()
+{
+    echo "$(fetch_data $1)" | tail -1 | cut -d ' ' -f $(expr $2 + 2)
+}
+
+case "$type" in
+    radius_rtx)
+        col=2
+        rrd_data=$(fetch_data 'AVERAGE')
+        for var in `echo "$rrd_data" | head -1`; do
+            case "$var" in
+                1) printf "one.value ";;
+                2) printf "two.value ";;
+                3) printf "three.value ";;
+                4) printf "four.value ";;
+                *) printf "$var.value ";;
+            esac
+            echo "$rrd_data" | tail -1 | cut -d ' ' -f $col
+            col=`expr $col + 1`
+        done
+        ;;
+
+    radius_count)
+        col=2
+        rrd_data=$(fetch_data 'AVERAGE')
+        for var in `echo "$rrd_data" | head -1`; do
+            printf "$var.value "
+            echo "$rrd_data" | tail -1 | cut -d ' ' -f $col
+            col=`expr $col + 1`
+        done
+        ;;
+
+    radius_latency)
+        printf "smoothed.value "
+        fetch_data_column 'AVERAGE' 0
+
+        printf "avg.value "
+        fetch_data_column 'AVERAGE' 1
+
+        # Averages here are unacceptable because we use this to detect
+        # abnormally long delays in responses, and if we average all the highs
+        # over a five minute period, transient spikes in latency may be lost.
+        printf "high.value "
+        fetch_data_column 'MAX' 2
+
+        # Again we need the lowest value of the set here, as an abnormally
+        # quick response may indicate something is wrong.
+        printf "low.value "
+        fetch_data_column 'MIN' 3
+        ;;
+esac
+exit 0
index 1d322e6..f10b291 100755 (executable)
 #
 
 usage() {
-    printf "Usage: %s: [-c condition] [-d directory] [-i client-ip-address] [-I client-ipv6-address] [-f socket_file] [-t timeout] [-u user]\n" $(basename $0) >&2
+    printf "Usage: %s: [-c condition] [-d directory] [-D dictdir]  [-i client-ip-address] [-I client-ipv6-address] [-f socket_file] [-t timeout] [-u user]\n" $(basename $0) >&2
     exit 2
 }
 
 extra=
 condition=1
 timeout=60
-while getopts 'd:c:i:I:f:t:u:' OPTION
+while getopts 'd:D:c:i:I:f:t:u:' OPTION
 do
   case $OPTION in
   c)   condition="$OPTARG"
        ;;
-  d)    [ "$extra" = "" ] || usage
-       extra="-d $OPTARG"
+  d)    extra="$extra -d $OPTARG"
        ;;
-  i)   condition="(Packet-Src-IP-Address == $OPTARG)"
+  D)    extra="$extra -D $OPTARG"
        ;;
-  I)   condition="(Packet-Src-IPv6-Address == $OPTARG)"
+  i)    x="(Packet-Src-IP-Address == $OPTARG)"
+       if [ "$condition" = "" ]; then
+           condition="$x"
+       else
+         condition="$condition && $x"
+       fi
        ;;
-  f)   [ "$extra" = "" ] || usage
-       extra="-f $OPTARG"
+  I)   x="(Packet-Src-IPv6-Address == $OPTARG)"
+       if [ "$condition" = "" ]; then
+           condition="$x"
+       else
+         condition="$condition && $x"
+       fi
+       ;;
+  f)   extra="$extra -f $OPTARG"
        ;;
   t)   timeout="$OPTARG"
        [ "$timeout" = "0" ] && timeout=1000000
        ;;
-  u)   condition="(User-Name == '$OPTARG')"
+  u)   x="(User-Name == '$OPTARG')"
+       if [ "$condition" = "" ]; then
+           condition="$x"
+       else
+         condition="$condition && $x"
+       fi
        ;;
   ?)   usage
        ;;
index 3a1efa9..f72acec 100755 (executable)
@@ -81,7 +81,7 @@ options:
        -f file         Read password from file, instead of command line.
        -h host         Connect to host.
        -P port         Port number to use for connection.
-       -p passord      Password to use when connecting to server.
+       -p password     Password to use when connecting to server.
        -u user         User for login.
        -x              Turn on debugging.
 HERE
index 8ca841e..1b34cce 100644 (file)
@@ -130,6 +130,7 @@ $INCLUDE dictionary.3gpp2
 $INCLUDE dictionary.acc
 $INCLUDE dictionary.acme
 $INCLUDE dictionary.actelis
+$INCLUDE dictionary.adtran
 $INCLUDE dictionary.airespace
 $INCLUDE dictionary.alcatel
 $INCLUDE dictionary.alcatel.sr
@@ -154,6 +155,7 @@ $INCLUDE dictionary.bt
 $INCLUDE dictionary.cablelabs
 $INCLUDE dictionary.cabletron
 $INCLUDE dictionary.camiant
+$INCLUDE dictionary.checkpoint
 $INCLUDE dictionary.chillispot
 $INCLUDE dictionary.cisco
 $INCLUDE dictionary.cisco.asa
@@ -193,6 +195,7 @@ $INCLUDE dictionary.foundry
 $INCLUDE dictionary.gandalf
 $INCLUDE dictionary.gemtek
 $INCLUDE dictionary.h3c
+$INCLUDE dictionary.hillstone
 $INCLUDE dictionary.hp
 $INCLUDE dictionary.huawei
 $INCLUDE dictionary.iea
@@ -204,11 +207,13 @@ $INCLUDE dictionary.juniper
 $INCLUDE dictionary.karlnet
 $INCLUDE dictionary.kineto
 $INCLUDE dictionary.lancom
+$INCLUDE dictionary.lantronix
 $INCLUDE dictionary.livingston
 $INCLUDE dictionary.localweb
 $INCLUDE dictionary.lucent
 $INCLUDE dictionary.manzara
 $INCLUDE dictionary.meinberg
+$INCLUDE dictionary.meraki
 $INCLUDE dictionary.merit
 $INCLUDE dictionary.meru
 $INCLUDE dictionary.microsoft
@@ -247,6 +252,7 @@ $INCLUDE dictionary.riverstone
 $INCLUDE dictionary.roaringpenguin
 $INCLUDE dictionary.ruggedcom
 $INCLUDE dictionary.ruckus
+$INCLUDE dictionary.sangoma
 $INCLUDE dictionary.shasta
 $INCLUDE dictionary.sg
 $INCLUDE dictionary.shiva
index b136127..183ee7f 100644 (file)
@@ -42,6 +42,11 @@ ATTRIBUTE    3GPP-SGSN-MCC-MNC                       18      string
 ATTRIBUTE      3GPP-Teardown-Indicator                 19      byte
 ATTRIBUTE      3GPP-IMEISV                             20      string
 ATTRIBUTE      3GPP-RAT-Type                           21      byte
+
+#
+#  See http://www.3gpp.org/DynaReport/29061.htm
+#      http://www.3gpp.org/DynaReport/29274.htm
+#
 ATTRIBUTE      3GPP-Location-Info                      22      octets
 ATTRIBUTE      3GPP-MS-Time-Zone                       23      octets[2]
 ATTRIBUTE      3GPP-Camel-Charging-Info                24      octets
diff --git a/share/dictionary.adtran b/share/dictionary.adtran
new file mode 100644 (file)
index 0000000..d4aa6dd
--- /dev/null
@@ -0,0 +1,17 @@
+# -*- text -*-
+# Copyright (C) 2015 The FreeRADIUS Server project and contributors
+#
+
+VENDOR         Adtran                          664
+
+BEGIN-VENDOR   Adtran
+
+# Managed WiFi attributes
+
+ATTRIBUTE      Adtran-AP-Name                          100     string
+ATTRIBUTE      Adtran-AP-IP                            101     ipaddr
+ATTRIBUTE      Adtran-AP-Template                      102     string
+ATTRIBUTE      Adtran-SSID                             103     string
+ATTRIBUTE      Adtran-Role                             104     string
+
+END-VENDOR Adtran
index 27d693c..82621cd 100644 (file)
@@ -10,5 +10,8 @@ VENDOR                Arista                          30065
 BEGIN-VENDOR   Arista
 
 ATTRIBUTE      Arista-AVPair                   1       string
+ATTRIBUTE       Arista-User-Priv-Level          2       integer
+ATTRIBUTE       Arista-User-Role                3       string
+ATTRIBUTE       Arista-CVP-Role                 4       string
 
 END-VENDOR   Arista
index 8196dac..c0d3955 100644 (file)
@@ -51,6 +51,10 @@ ATTRIBUTE    Aruba-AirGroup-Version                  38      integer
 
 ATTRIBUTE      Aruba-Port-Bounce-Host                  40      integer
 
+ATTRIBUTE      Aruba-Calea-Server-Ip                   41      ipaddr
+
+ATTRIBUTE      Aruba-Admin-Path                        42      string
+
 VALUE  Aruba-AirGroup-Device-Type      Personal-Device         1
 VALUE  Aruba-AirGroup-Device-Type      Shared-Device           2
 
diff --git a/share/dictionary.checkpoint b/share/dictionary.checkpoint
new file mode 100644 (file)
index 0000000..82d000d
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# Copyright (C) 2016 The FreeRADIUS Server project and contributors
+#
+#      Check Point dictionary file for freeradius AAA server
+#
+VENDOR         CheckPoint                      2620
+
+BEGIN-VENDOR   CheckPoint
+
+ATTRIBUTE      CP-Gaia-User-Role                       229     string
+ATTRIBUTE      CP-Gaia-SuperUser-Access                230     integer
+
+END-VENDOR     CheckPoint
index 5de613e..f142f94 100644 (file)
@@ -143,4 +143,44 @@ ATTRIBUTE  FreeRADIUS-Queue-Use-Percentage         183     integer
 ATTRIBUTE      FreeRADIUS-Stats-Last-Packet-Recv       184     date
 ATTRIBUTE      FreeRADIUS-Stats-Last-Packet-Sent       185     date
 
+#
+# EAP-FAST TLVs
+#
+ATTRIBUTE      FreeRADIUS-EAP-FAST-TLV                         186     tlv
+ATTRIBUTE      FreeRADIUS-EAP-FAST-Result                              186.3   short
+ATTRIBUTE      FreeRADIUS-EAP-FAST-NAK                         186.4   octets
+ATTRIBUTE      FreeRADIUS-EAP-FAST-Error                               186.5   integer
+ATTRIBUTE      FreeRADIUS-EAP-FAST-Vendor-Specific             186.7   octets
+ATTRIBUTE      FreeRADIUS-EAP-FAST-EAP-Payload                 186.9   octets
+ATTRIBUTE      FreeRADIUS-EAP-FAST-Intermediate-Result         186.10  octets
+
+ATTRIBUTE      FreeRADIUS-EAP-FAST-PAC                 186.11  tlv
+ATTRIBUTE      FreeRADIUS-EAP-FAST-PAC-Key                     186.11.1 octets
+
+ATTRIBUTE      FreeRADIUS-EAP-FAST-PAC-Opaque-TLV                      186.11.2 tlv
+ATTRIBUTE      FreeRADIUS-EAP-FAST-PAC-Opaque-PAC-Key          186.11.2.1 octets
+ATTRIBUTE      FreeRADIUS-EAP-FAST-PAC-Opaque-PAC-Lifetime     186.11.2.3 integer
+ATTRIBUTE      FreeRADIUS-EAP-FAST-PAC-Opaque-I-ID             186.11.2.5 octets
+ATTRIBUTE      FreeRADIUS-EAP-FAST-PAC-Opaque-PAC-Type         186.11.2.10 short
+
+ATTRIBUTE      FreeRADIUS-EAP-FAST-PAC-Lifetime                        186.11.3 integer
+ATTRIBUTE      FreeRADIUS-EAP-FAST-PAC-A-ID                    186.11.4 octets
+ATTRIBUTE      FreeRADIUS-EAP-FAST-PAC-I-ID                    186.11.5 octets
+ATTRIBUTE      FreeRADIUS-EAP-FAST-PAC-A-ID-Info                       186.11.7 octets
+ATTRIBUTE      FreeRADIUS-EAP-FAST-PAC-Acknowledge             186.11.8 short
+ATTRIBUTE      FreeRADIUS-EAP-FAST-PAC-Info-TLV                        186.11.9 tlv
+ATTRIBUTE      FreeRADIUS-EAP-FAST-PAC-Info-PAC-Lifetime               186.11.9.3 integer
+ATTRIBUTE      FreeRADIUS-EAP-FAST-PAC-Info-A-ID                       186.11.9.4 octets
+ATTRIBUTE      FreeRADIUS-EAP-FAST-PAC-Info-I-ID                       186.11.9.5 octets
+ATTRIBUTE      FreeRADIUS-EAP-FAST-PAC-Info-A-ID-Info          186.11.9.7 octets
+ATTRIBUTE      FreeRADIUS-EAP-FAST-PAC-Info-PAC-Type           186.11.9.10 short
+
+ATTRIBUTE      FreeRADIUS-EAP-FAST-PAC-Type                    186.11.10 short
+
+ATTRIBUTE      FreeRADIUS-EAP-FAST-Crypto-Binding                      186.12  octets
+
+ATTRIBUTE      FreeRADIUS-EAP-FAST-Trusted-Root                        186.18  octets
+ATTRIBUTE      FreeRADIUS-EAP-FAST-Request-Action                      186.19  short
+ATTRIBUTE      FreeRADIUS-EAP-FAST-PKCS                                186.20  octets
+
 END-VENDOR FreeRADIUS
index 93e1443..03a73fd 100644 (file)
@@ -232,8 +232,6 @@ ATTRIBUTE   OTP-Challenge                           1145    string
 ATTRIBUTE      EAP-Session-Id                          1146    octets
 ATTRIBUTE      Chbind-Response-Code                    1147    integer
 
-ATTRIBUTE      Chbind-Response-Code                    1147    integer
-
 VALUE  Chbind-Response-Code            success                 2
 VALUE  Chbind-Response-Code            failure                 3
 
@@ -272,6 +270,8 @@ ATTRIBUTE   SSHA2-256-Password                      1178    octets
 ATTRIBUTE      SSHA2-384-Password                      1179    octets
 ATTRIBUTE      SSHA2-512-Password                      1180    octets
 
+ATTRIBUTE      MS-CHAP-Peer-Challenge                  1192    octets
+
 #
 #      Range:  1200-1279
 #              EAP-SIM (and other EAP type) weirdness.
@@ -308,6 +308,9 @@ ATTRIBUTE   EAP-Sim-KC3                             1214    octets
 ATTRIBUTE      EAP-Sim-Ki                              1215    octets
 ATTRIBUTE      EAP-Sim-Algo-Version                    1216    integer
 
+ATTRIBUTE      Outer-Realm-Name                        1218    string
+ATTRIBUTE      Inner-Realm-Name                        1219    string
+
 #
 #      Range:  1280 - 1535
 #              EAP-type specific attributes
@@ -533,6 +536,15 @@ ATTRIBUTE  TLS-PSK-Identity                        1933    string
 
 # 1934 - 1939: reserved for future cert attributes
 
+# 1940 - 1949: reserved for TLS session caching, mostly in 3.1
+
+# Set by EAP-TLS code
+ATTRIBUTE      TLS-OCSP-Cert-Valid                     1943    integer
+VALUE  TLS-OCSP-Cert-Valid             unknown                 3
+VALUE  TLS-OCSP-Cert-Valid             skipped                 2
+VALUE  TLS-OCSP-Cert-Valid             yes                     1
+VALUE  TLS-OCSP-Cert-Valid             no                      0
+
 #
 #      Range:  1940-2099
 #              Free
@@ -596,31 +608,13 @@ ATTRIBUTE Radclient-Test-Name                     2200    string
 #
 
 VALUE  Auth-Type                       Local                   1
-VALUE  Auth-Type                       System                  2
-VALUE  Auth-Type                       SecurID                 3
 VALUE  Auth-Type                       Reject                  4
-VALUE  Auth-Type                       ActivCard               5
-VALUE  Auth-Type                       EAP                     6
 
 #
 #      FreeRADIUS extensions (most originally from Cistron)
 #
 VALUE  Auth-Type                       Accept                  254
 
-VALUE  Auth-Type                       PAP                     1024
-VALUE  Auth-Type                       CHAP                    1025
-# 1026 was LDAP, but we deleted it.  Adding it back will break the
-# ldap module.
-VALUE  Auth-Type                       PAM                     1027
-VALUE  Auth-Type                       MS-CHAP                 1028
-VALUE  Auth-Type                       MSCHAP                  1028
-VALUE  Auth-Type                       Kerberos                1029
-VALUE  Auth-Type                       CRAM                    1030
-VALUE  Auth-Type                       NS-MTA-MD5              1031
-# 1032 is unused (was a duplicate of CRAM)
-VALUE  Auth-Type                       SMB                     1033
-VALUE  Auth-Type                       MS-CHAP-V2              1034
-
 #
 #      Authorization type, too.
 #
@@ -799,7 +793,7 @@ VALUE       EAP-Type                        IKEv2                   49
 VALUE  EAP-Type                        AKA2                    50
 VALUE  EAP-Type                        GPSK                    51
 VALUE  EAP-Type                        PWD                     52
-VALUE  EAP-Type                        EVEv1                   53
+VALUE  EAP-Type                        EKEv1                   53
 
 #
 #      And this is what most people mean by MS-CHAPv2
diff --git a/share/dictionary.hillstone b/share/dictionary.hillstone
new file mode 100644 (file)
index 0000000..15e1eaa
--- /dev/null
@@ -0,0 +1,49 @@
+# -*- text -*-
+# Copyright (C) 2015 The FreeRADIUS Server project and contributors
+##############################################################################
+#
+#      From yqsi@hillstonenet.com 2015/11/2
+#
+#      $Id$
+#
+##############################################################################
+
+VENDOR         Hillstone                       28557
+
+BEGIN-VENDOR   Hillstone
+
+ATTRIBUTE      Hillstone-User-vsys-id                  1       integer
+ATTRIBUTE      Hillstone-User-Type                     2       integer
+ATTRIBUTE      Hillstone-User-Admin-Privilege          3       integer
+ATTRIBUTE      Hillstone-User-Login-Type               4       integer
+ATTRIBUTE      Hillstone-User-Mobile-Number            5       string
+ATTRIBUTE      Hillstone-User-Mobile-Operator          6       integer
+ATTRIBUTE      Hillstone-User-Policy-dst-ip-begin      7       ipaddr
+ATTRIBUTE      Hillstone-User-Policy-dst-ip-end        8       ipaddr
+ATTRIBUTE      Hillstone-User-Role-Bame                9       string
+ATTRIBUTE      Hillstone-VPN-DHCP-Gateway              100     string
+ATTRIBUTE      Hillstone-VPN-DHCP-Mask                 101     string
+ATTRIBUTE      Hillstone-VPN-DHCP-Pool                 102     string
+ATTRIBUTE      Hillstone-VPN-WINS                      103     string
+ATTRIBUTE      Hillstone-VPN-DNS                       104     string
+ATTRIBUTE      Hillstone-VPN-Split-Route               105     string
+ATTRIBUTE      Hillstone-VPN-Tunnel-IP                 106     string
+ATTRIBUTE      Hillstone-VPN-SNAT                      107     integer
+
+VALUE  Hillstone-User-Type             HS-User-l2tp            1
+VALUE  Hillstone-User-Type             HS-User-8021x           2
+VALUE  Hillstone-User-Type             HS-User-smartvpn        4
+VALUE  Hillstone-User-Type             HS-User-normal          8
+VALUE  Hillstone-User-Type             HS-User-Admin           16
+
+VALUE  Hillstone-User-Login-Type       HS-Admin-Console        1
+VALUE  Hillstone-User-Login-Type       HS-Admin-Telnet         2
+VALUE  Hillstone-User-Login-Type       HS-Admin-SSH            4
+VALUE  Hillstone-User-Login-Type       HS-Admin-HTTP           8
+VALUE  Hillstone-User-Login-Type       HS-Admin-HTTPS          16
+
+VALUE  Hillstone-User-Mobile-Operator  HS-Mobile-ChinaMobile   1
+VALUE  Hillstone-User-Mobile-Operator  HS-Mobile-ChinaUnicom   2
+VALUE  Hillstone-User-Mobile-Operator  HS-Mobile-ChinaTelecom  3
+
+END-VENDOR      Hillstone
index 0a56038..4df7faf 100644 (file)
@@ -26,6 +26,8 @@ ATTRIBUTE     HP-Port-Client-Limit-Dot1x              10      integer
 ATTRIBUTE      HP-Port-Client-Limit-MA                 11      integer
 ATTRIBUTE      HP-Port-Client-Limit-WA                 12      integer
 ATTRIBUTE      HP-Port-Auth-Mode-Dot1x                 13      integer
+ATTRIBUTE      HP-Port-Bounce-Host                     23      integer
+ATTRIBUTE      HP-Captive-Portal-URL                   24      string
 
 # Client QoS attributes
 ATTRIBUTE      HP-Port-Priority-Regeneration-Table     40      string
index d556d95..f25730d 100644 (file)
@@ -157,7 +157,7 @@ ATTRIBUTE   Huawei-NAT-Port-Forwarding              164     string
 ATTRIBUTE      Huawei-NAT-Port-Range-Update            165     integer
 ATTRIBUTE      Huawei-DS-Lite-Tunnel-Name              166     string
 ATTRIBUTE      Huawei-PCP-Server-Name                  167     string # manual says text?
-ATTRIBUTE      Huawei-Public-IP-Addr-State             168     Integer
+ATTRIBUTE      Huawei-Public-IP-Addr-State             168     integer
 
 VALUE  Huawei-Public-IP-Addr-State     Safe                    0
 VALUE  Huawei-Public-IP-Addr-State     Warning                 1
@@ -193,7 +193,7 @@ ATTRIBUTE   Huawei-Delegated-IPv6-Prefix-Pool       191     string
 ATTRIBUTE      Huawei-IPv6-Prefix-Lease                192     octets
 ATTRIBUTE      Huawei-IPv6-Address-Lease               193     octets
 ATTRIBUTE      Huawei-IPv6-Policy-Route                194     ipv6prefix # manual says string?
-ATTRIBUTE      Huawei-MNG-IPv6                         196     Integer
+ATTRIBUTE      Huawei-MNG-IPv6                         196     integer
 
 VALUE  Huawei-MNG-IPv6                 Unsupported             0
 VALUE  Huawei-MNG-IPv6                 Supported               1
index 2971d14..c29f3d6 100644 (file)
@@ -21,5 +21,21 @@ ATTRIBUTE    LCS-WPA-Passphrase                      6       string
 ATTRIBUTE      LCS-PbSpotUserName                      7       string
 ATTRIBUTE      LCS-TxRateLimit                         8       integer
 ATTRIBUTE      LCS-RxRateLimit                         9       integer
+ATTRIBUTE      LCS-Access-Rights                       11      integer
+ATTRIBUTE      LCS-Function-Rights                     12      integer
+ATTRIBUTE      LCS-Advertisement-URL                   13      string
+ATTRIBUTE      LCS-Advertisement-Interval              14      integer
+ATTRIBUTE      LCS-Traffic-Limit-Gigawords             15      integer
+ATTRIBUTE      LCS-Orig-NAS-Identifier                 16      string
+ATTRIBUTE      LCS-Orig-NAS-IP-Address                 17      ipaddr
+ATTRIBUTE      LCS-Orig-NAS-IPv6-Address               18      ipv6addr
+ATTRIBUTE      LCS-IKEv2-Local-Password                19      string  has_tag,encrypt=2
+ATTRIBUTE      LCS-IKEv2-Remote-Password               20      string  has_tag,encrypt=2
+ATTRIBUTE      LCS-DNS-Server-IPv4-Address             21      ipaddr
+ATTRIBUTE      LCS-VPN-IPv4-Rule                       22      string
+ATTRIBUTE      LCS-VPN-IPv6-Rule                       23      string
+ATTRIBUTE      LCS-Routing-Tag                         24      integer
+ATTRIBUTE      LCS-IKEv2-IPv4-Route                    25      string
+ATTRIBUTE      LCS-IKEv2-IPv6-Route                    26      string
 
 END-VENDOR   Lancom
diff --git a/share/dictionary.lantronix b/share/dictionary.lantronix
new file mode 100644 (file)
index 0000000..dbbd274
--- /dev/null
@@ -0,0 +1,12 @@
+# dictionary.lantronix
+#
+# Lantronix SLC Secure Lantronix Console Manager
+# Provides SLC-specific user attributes
+#
+VENDOR Lantronix 244
+
+BEGIN-VENDOR Lantronix
+
+ATTRIBUTE      Lantronix-User-Attributes               1       string
+
+END-VENDOR Lantronix
diff --git a/share/dictionary.meraki b/share/dictionary.meraki
new file mode 100644 (file)
index 0000000..b531497
--- /dev/null
@@ -0,0 +1,12 @@
+# -*- text -*-
+# Copyright (C) 2015 The FreeRADIUS Server project and contributors
+#
+#       For Meraki.
+#
+
+VENDOR          Meraki                          29671
+BEGIN-VENDOR    Meraki
+
+ATTRIBUTE       Meraki-Device-Name                      1       string
+
+END-VENDOR      Meraki
index 42000de..974750a 100644 (file)
@@ -2,7 +2,7 @@
 # Copyright (C) 2015 The FreeRADIUS Server project and contributors
 #
 #      Attributes and values defined in RFC 4072
-#      http://www.ietf.org/rfc/4072.txt
+#      http://www.ietf.org/rfc/rfc4072.txt
 #
 #      $Id$
 #
index 3e6e523..1fe1335 100644 (file)
@@ -2,7 +2,7 @@
 # Copyright (C) 2015 The FreeRADIUS Server project and contributors
 #
 #      Attributes and values defined in RFC 4372.
-#      http://www.ietf.org/rfc/4372.txt
+#      http://www.ietf.org/rfc/rfc4372.txt
 #
 #      $Id$
 #
index 5953ec4..d615722 100644 (file)
@@ -2,7 +2,7 @@
 # Copyright (C) 2015 The FreeRADIUS Server project and contributors
 #
 #      Attributes and values defined in RFC 4675.
-#      http://www.ietf.org/rfc/4675.txt
+#      http://www.ietf.org/rfc/rfc4675.txt
 #
 #      $Id$
 #
index cc81286..6c6f1dc 100644 (file)
@@ -2,7 +2,7 @@
 # Copyright (C) 2015 The FreeRADIUS Server project and contributors
 #
 #      Attributes and values defined in RFC 4679.
-#      http://www.ietf.org/rfc/4679.txt
+#      http://www.ietf.org/rfc/rfc4679.txt
 #
 #      $Id$
 #
index bc803a6..82d63c3 100644 (file)
 #
 #
 
-VENDOR         Ruckus                          25053
+VENDOR        Ruckus                25053
 
-BEGIN-VENDOR   Ruckus
+BEGIN-VENDOR    Ruckus
 
-ATTRIBUTE      Ruckus-User-Groups                      1       string
-# Value Format: group_attr1,group_attr2,...
+# Value Format:    group_attr1,group_attr2,...
+ATTRIBUTE       Ruckus-User-Groups                 1      string
+ATTRIBUTE       Ruckus-Sta-RSSI                    2      integer
+ATTRIBUTE       Ruckus-SSID                        3      string
+ATTRIBUTE       Ruckus-Wlan-Id                     4      integer 
+ATTRIBUTE       Ruckus-Location                    5      string
+ATTRIBUTE       Ruckus-Grace-Period                6      integer
+ATTRIBUTE       Ruckus-SCG-CBlade-IP               7      integer
+ATTRIBUTE       Ruckus-SCG-DBlade-IP               8      integer
+ATTRIBUTE       Ruckus-VLAN-ID                     9      integer
+ATTRIBUTE       Ruckus-Sta-Expiration              10     integer # not used by AP anymore. Please check SCG-33602
+ATTRIBUTE       Ruckus-Sta-UUID                    11     string
+ATTRIBUTE       Ruckus-Accept-Enhancement-Reason   12     integer 
+ATTRIBUTE       Ruckus-Sta-Inner-Id                13     string
+ATTRIBUTE       Ruckus-BSSID                       14     octets
 
-ATTRIBUTE      Ruckus-Sta-RSSI                         2       integer
-ATTRIBUTE      Ruckus-SSID                             3       string
-ATTRIBUTE      Ruckus-WlanID                           4       integer
-ATTRIBUTE      Ruckus-Location                         5       string
-ATTRIBUTE      Ruckus-Grace-Period                     6       integer
-# Sent to the server, range: 1 to 14400 [minutes]
+ATTRIBUTE       Ruckus-WSG-User                    10     string
 
-ATTRIBUTE      Ruckus-SCG-CBlade-IP                    7       integer
-ATTRIBUTE      Ruckus-SCG-DBlade-IP                    8       integer
-ATTRIBUTE      Ruckus-Session-Type                     125     integer
-ATTRIBUTE      Ruckus-Acct-Status                      126     integer
+ATTRIBUTE       Ruckus-Triplets                    101    octets
+ATTRIBUTE       Ruckus-IMSI                        102    octets
+ATTRIBUTE       Ruckus-MSISDN                      103    octets
+ATTRIBUTE       Ruckus-APN-NI                      104    string
+ATTRIBUTE       Ruckus-QoS                         105    octets
+ATTRIBUTE       Ruckus-Selection-Mode              106    integer
+ATTRIBUTE       Ruckus-APN-Resolution-Req          107    integer
+ATTRIBUTE       Ruckus-Start-Time                  108    octets
+ATTRIBUTE       Ruckus-NAS-Type                    109    integer
+ATTRIBUTE       Ruckus-Status                      110    integer
+ATTRIBUTE       Ruckus-APN-OI                      111    string
+ATTRIBUTE       Ruckus-Auth-Type                   112    integer
+ATTRIBUTE       Ruckus-Gn-User-Name                113    string
+ATTRIBUTE       Ruckus-Brand-Code                  114    string
+ATTRIBUTE       Ruckus-Policy-Name                 115    string
+ATTRIBUTE       Ruckus-Client-Local-IP             116    ipaddr
+ATTRIBUTE       Ruckus-SGSN-IP                     117    ipaddr
+ATTRIBUTE       Ruckus-Charging-Charac             118    octets 
+ATTRIBUTE       Ruckus-PDP-Type                    119    octets
+ATTRIBUTE       Ruckus-Dynamic-Address-Flag        120    octets
+ATTRIBUTE       Ruckus-ChCh-Selection-Mode         121    octets
+ATTRIBUTE       Ruckus-AAA-IP                      122    ipaddr
+ATTRIBUTE       Ruckus-CDR-TYPE                    123    integer
+ATTRIBUTE       Ruckus-SGSN-Number                 124    octets
+ATTRIBUTE       Ruckus-Session-Type                125    integer
+ATTRIBUTE       Ruckus-Accounting-Status           126    integer
+ATTRIBUTE       Ruckus-Zone-Id                     127    string
+ATTRIBUTE       Ruckus-Auth-Server-Id              128    string
+ATTRIBUTE       Ruckus-Utp-Id                      129    string
+ATTRIBUTE       Ruckus-Area-Code                   130    octets 
+ATTRIBUTE       Ruckus-Cell-Identifier             131    octets 
+ATTRIBUTE       Ruckus-Wispr-Redirect-Policy       132    string
+ATTRIBUTE       Ruckus-Eth-Profile-Id              133    integer
+ATTRIBUTE       Ruckus-Zone-Name                   134    string
+ATTRIBUTE       Ruckus-Wlan-Name                   135    string
 
-END-VENDOR      Ruckus
+#
+#  Integer Translations
+#
+
+#  Ruckus-Selection-Mode Values
+
+VALUE    Ruckus-Selection-Mode      Subscribed      0
+VALUE    Ruckus-Selection-Mode      SentByMS        1
+VALUE    Ruckus-Selection-Mode      ChosenBySGSN    2
+
+#  Ruckus-APN-Resolution-Req Values
+
+VALUE        Ruckus-APN-Resolution-Req    NotRequired    0
+VALUE        Ruckus-APN-Resolution-Req    Required       1
+
+#  Ruckus-Status Values
+
+VALUE        Ruckus-Status    Success    0
+VALUE        Ruckus-Status    Failure    1
+
+#  Ruckus-Auth-Type Values
+
+VALUE        Ruckus-Auth-Type    PPP-SIM            1
+VALUE        Ruckus-Auth-Type    DummyIMSI          2
+VALUE        Ruckus-Auth-Type    SoftSIM            3
+VALUE        Ruckus-Auth-Type    RadiusSIM          4
+VALUE        Ruckus-Auth-Type    Postpaid           5
+VALUE        Ruckus-Auth-Type    Prepaid            6
+VALUE        Ruckus-Auth-Type    LocalRadius        7
+VALUE        Ruckus-Auth-Type    ProxyRadius        8
+VALUE        Ruckus-Auth-Type    Voucher            9
+VALUE        Ruckus-Auth-Type    EAP-SIM            10
+
+# Ruckus-Session-Type Values
+# Updated as per SCG2.1
+#Value (1) No more valid for SCG2.1
+VALUE        Ruckus-Session-Type    TTG                 2
+VALUE        Ruckus-Session-Type    Local-Breakout      3
+VALUE        Ruckus-Session-Type    Local-Breakout-AP   4
+VALUE        Ruckus-Session-Type    L3GRE               5
+VALUE        Ruckus-Session-Type    L2GRE               6
+VALUE        Ruckus-Session-Type    QinQL3              7
+VALUE        Ruckus-Session-Type    PMIP                8
+
+
+#RUCKUS-NAS_Type 
+
+VALUE        Ruckus-NAS-Type     SCG                1
+VALUE        Ruckus-NAS-Type     Others             2  
+
+#Ruckus-Accounting-Status
+VALUE        Ruckus-Accounting-Status     Accounting-On          1
+VALUE        Ruckus-Accounting-Status     Accounting-Off         0
+
+END-VENDOR Ruckus
diff --git a/share/dictionary.sangoma b/share/dictionary.sangoma
new file mode 100644 (file)
index 0000000..1f7bc2a
--- /dev/null
@@ -0,0 +1,112 @@
+# -*- text -*-
+#
+# dictionary.sangoma
+#
+# jma@sangoma.com
+#
+# Version:     $Id: dictionary.sangoma
+#
+
+VENDOR         NetBorder                       35987
+
+#
+#      Standard attribute
+#
+BEGIN-VENDOR   NetBorder
+
+ATTRIBUTE      NetBorder-AVPair                        1       string
+ATTRIBUTE      NetBorder-CLID                          2       string
+ATTRIBUTE      NetBorder-Dialplan                      3       string
+ATTRIBUTE      NetBorder-Src                           4       string
+ATTRIBUTE      NetBorder-Dst                           5       string
+ATTRIBUTE      NetBorder-Src-Channel                   6       string
+ATTRIBUTE      NetBorder-Dst-Channel                   7       string
+ATTRIBUTE      NetBorder-Ani                           8       string
+ATTRIBUTE      NetBorder-Aniii                         9       string
+ATTRIBUTE      NetBorder-Lastapp                       10      string
+ATTRIBUTE      NetBorder-Lastdata                      11      string
+ATTRIBUTE      NetBorder-Disposition                   12      string
+ATTRIBUTE      NetBorder-Hangupcause                   13      integer
+ATTRIBUTE      NetBorder-Billusec                      15      integer
+ATTRIBUTE      NetBorder-AMAFlags                      16      integer
+ATTRIBUTE      NetBorder-RDNIS                         17      string
+ATTRIBUTE      NetBorder-Context                       18      string
+ATTRIBUTE      NetBorder-Source                        19      string
+ATTRIBUTE      NetBorder-Callstartdate                 20      string
+ATTRIBUTE      NetBorder-Callanswerdate                21      string
+ATTRIBUTE      NetBorder-Calltransferdate              22      string
+ATTRIBUTE      NetBorder-Callenddate                   23      string
+ATTRIBUTE      NetBorder-Signalbond                    24      string
+
+#
+#  NetBorder-Hangupcause
+#
+VALUE  NetBorder-Hangupcause           None                    0
+VALUE  NetBorder-Hangupcause           Unallocated-Number      1
+VALUE  NetBorder-Hangupcause           No-Route-Transit-Net    2
+VALUE  NetBorder-Hangupcause           No-Route-Destination    3
+VALUE  NetBorder-Hangupcause           Channel-Unacceptable    6
+VALUE  NetBorder-Hangupcause           Call-Awarded-Delivery   7
+VALUE  NetBorder-Hangupcause           Normal-Clearing         16
+VALUE  NetBorder-Hangupcause           User-Busy               17
+VALUE  NetBorder-Hangupcause           No-User-Response        18
+VALUE  NetBorder-Hangupcause           No-Answer               19
+VALUE  NetBorder-Hangupcause           Subscriber-Absent       20
+VALUE  NetBorder-Hangupcause           Call-Rejected           21
+VALUE  NetBorder-Hangupcause           Number-Changed          22
+VALUE  NetBorder-Hangupcause           Redirecto-To-New-Destination 23
+VALUE  NetBorder-Hangupcause           Exchange-Routing-Error  25
+VALUE  NetBorder-Hangupcause           Destination-Out-Of-Order 27
+VALUE  NetBorder-Hangupcause           Invalid-Number-Format   28
+VALUE  NetBorder-Hangupcause           Facility-Rejected       29
+VALUE  NetBorder-Hangupcause           Response-To-Status-Enquiry 30
+VALUE  NetBorder-Hangupcause           Normal-Unspecified      31
+VALUE  NetBorder-Hangupcause           Normal-Circuit-Congestion 34
+VALUE  NetBorder-Hangupcause           Network-Out-Of-Order    38
+VALUE  NetBorder-Hangupcause           Normal-Temporary-Failure 41
+VALUE  NetBorder-Hangupcause           Switch-Congestion       42
+VALUE  NetBorder-Hangupcause           Access-Info-Discarded   43
+VALUE  NetBorder-Hangupcause           Requested-Chan-Unavail  44
+VALUE  NetBorder-Hangupcause           Pre-Empted              45
+VALUE  NetBorder-Hangupcause           Facility-Not-Subscribed 50
+VALUE  NetBorder-Hangupcause           Outgoing-Call-Barred    52
+VALUE  NetBorder-Hangupcause           Incoming-Call-Barred    54
+VALUE  NetBorder-Hangupcause           Bearercapability-Notauth 57
+VALUE  NetBorder-Hangupcause           Bearercapability-Notavail 58
+VALUE  NetBorder-Hangupcause           Service-Unavailable     63
+VALUE  NetBorder-Hangupcause           Bearercapability-Notimpl 65
+VALUE  NetBorder-Hangupcause           Chan-Not-Implemented    66
+VALUE  NetBorder-Hangupcause           Facility-Not-Implemented 69
+VALUE  NetBorder-Hangupcause           Service-Not-Implemented 79
+VALUE  NetBorder-Hangupcause           Invalid-Call-Reference  81
+VALUE  NetBorder-Hangupcause           Incompatible-Destination 88
+VALUE  NetBorder-Hangupcause           Invalid-Msg-Unspecified 95
+VALUE  NetBorder-Hangupcause           Mandatory-IE-Missing    96
+VALUE  NetBorder-Hangupcause           Message-Type-Nonexist   97
+VALUE  NetBorder-Hangupcause           Wrong-Message           98
+VALUE  NetBorder-Hangupcause           IE-Nonexist             99
+VALUE  NetBorder-Hangupcause           Invalid-IE-Contents     100
+VALUE  NetBorder-Hangupcause           Wrong-Call-State        101
+VALUE  NetBorder-Hangupcause           Recovery-On-Timer-Expire 102
+VALUE  NetBorder-Hangupcause           Mandatory-IE-Length-Error 103
+VALUE  NetBorder-Hangupcause           Protocol-Error          111
+VALUE  NetBorder-Hangupcause           Interworking            127
+VALUE  NetBorder-Hangupcause           Success                 142
+VALUE  NetBorder-Hangupcause           Originator-Cancel       487
+VALUE  NetBorder-Hangupcause           Crash                   500
+VALUE  NetBorder-Hangupcause           System-Shutdown         501
+VALUE  NetBorder-Hangupcause           Lose-Race               502
+VALUE  NetBorder-Hangupcause           Manager-Request         503
+VALUE  NetBorder-Hangupcause           Blind-Transfer          600
+VALUE  NetBorder-Hangupcause           Attended-Transfer       601
+VALUE  NetBorder-Hangupcause           Allotted-Timeout        602
+VALUE  NetBorder-Hangupcause           User-Challenge          603
+VALUE  NetBorder-Hangupcause           Media-Timeout           604
+VALUE  NetBorder-Hangupcause           Picked-Off              605
+VALUE  NetBorder-Hangupcause           User-Not-Registered     606
+
+#
+#
+#
+
+END-VENDOR     NetBorder
index 5a40610..12f6405 100644 (file)
@@ -228,7 +228,7 @@ ATTRIBUTE   SN-Firewall-Policy                      239     octets
 ATTRIBUTE      SN-Transparent-Data                     247     octets
 ATTRIBUTE      SN-MS-ISDN                              248     octets
 ATTRIBUTE      SN-Routing-Area-Id                      249     string
-#ATTRIBUTE     SN-Rulebase                             249     string
+ATTRIBUTE      SN-Rulebase                             250     string
 ATTRIBUTE      SN-Call-Id                              251     integer
 ATTRIBUTE      SN-IMSI                                 252     octets
 ATTRIBUTE      SN-Long-Duration-Notification           253     integer
@@ -284,7 +284,7 @@ ATTRIBUTE   SN-CBB-Policy                           302     string
 ATTRIBUTE      SN-QOS-HLR-Profile                      303     octets
 ATTRIBUTE      SN-Fast-Reauth-Username                 304     octets
 ATTRIBUTE      SN-Pseudonym-Username                   305     octets
-ATTRIBUTE      SN-WiMAX-Auth-Only                      206     integer
+ATTRIBUTE      SN-WiMAX-Auth-Only                      306     integer
 ATTRIBUTE      SN-TrafficSelector-Class                307     integer
 ATTRIBUTE      SN-DHCP-Options                         309     octets
 ATTRIBUTE      SN-Handoff-Indicator                    310     integer
index ead7a68..4cfa70c 100644 (file)
@@ -14,4 +14,12 @@ BEGIN-VENDOR Wichorus
 ATTRIBUTE      Wichorus-Policy-Name                    1       string
 ATTRIBUTE      Wichorus-User-Privilege                 2       string
 
+#
+#  Some versions of the Wichorus equipment use the following attribute.
+#  instead of Wichorus-User-Privilege.  This is considered to be
+#  bad practice.
+#
+
+#ATTRIBUTE     Wichorus-Host-IP                        2       ipaddr
+
 END-VENDOR     Wichorus
index b3dfdbd..d7a8a4f 100644 (file)
@@ -1,15 +1,4 @@
 # add this dependency BEFORE including the other submakefiles.
 all:
 
-#
-#  This nonsense is here because pattern rules don't work if you have
-#  multiple of them.  If you try to run the shell script by assigning
-#  it to a variable, GNU Make notices that the variable isn't used...
-#  and doesn't run the shell script.  This crap below seems to bypass
-#  Make's optimization.
-#
-ifeq "$(shell [ -e src/freeradius-devel ] || ln -s include src/freeradius-devel)" ""
-# do nothing
-endif
-
 SUBMAKEFILES := include/all.mk lib/all.mk modules/all.mk main/all.mk tests/all.mk
index c235349..2f4f429 100644 (file)
@@ -10,6 +10,10 @@ tls.h
 features.h
 radpaths.h
 vqp.h
+freeradius.h
+
+# Headers from v3.1.x
+freeradius.snmp.h
 
 # Build scripts
 build-radpaths-h
index 08c5668..396b679 100644 (file)
@@ -2,27 +2,35 @@
 # Version:     $Id$
 #
 
+#
+#  Build dynamic headers by substituting various values from autoconf.h, these
+#  get installed with the library files, so external programs can tell what
+#  the server library was built with.
+#
+#  The RFC headers are dynamic, too.
+#
+#  The rest of the headers are static.
+#
+
+HEADERS_DY = attributes.h features.h missing.h radpaths.h tls.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 \
@@ -31,16 +39,8 @@ HEADERS      = \
        token.h \
        udpfromto.h \
        base64.h \
-       map.h
-
-#
-#  Build dynamic headers by substituting various values from autoconf.h, these
-#  get installed with the library files, so external programs can tell what
-#  the server library was built with.
-#
-
-HEADERS_DY = src/include/features.h src/include/missing.h src/include/tls.h \
-       src/include/radpaths.h src/include/attributes.h
+       map.h \
+       $(HEADERS_DY)
 
 #
 #  Solaris awk doesn't recognise [[:blank:]] hence [\t ]
@@ -61,27 +61,23 @@ src/include/autoconf.sed: src/include/autoconf.h
 #  Create the header files from the dictionaries.
 #
 
-RFC_DICTS := $(filter-out %~,$(wildcard share/dictionary.rfc*))
-RFC_HEADERS := $(patsubst share/dictionary.%,src/include/%.h,$(RFC_DICTS))
+RFC_DICTS := $(filter-out %~,$(wildcard share/dictionary.rfc*)) share/dictionary.vqp share/dictionary.freeradius
+HEADERS_RFC := $(patsubst share/dictionary.%,src/include/%.h,$(RFC_DICTS))
+HEADERS        += $(notdir ${HEADERS_RFC})
+
+.PRECIOUS: $(HEADERS_RFC)
 
 src/include/attributes.h: share/dictionary.freeradius.internal
        @$(ECHO) HEADER $@
-       @grep ^ATTRIBUTE $<  | awk '{print "PW_"$$2 " " $$3 "   //!< AUTOGENERATED ATTRIBUTE DEFINITION"}' | tr '[:lower:]' '[:upper:]' | tr -- - _ | sed 's/^/#define /' > $@
+       @echo "/* AUTO-GENERATED HEADER FILE.  DO NOT EDIT. */" > $@
+       @grep ^ATTRIBUTE $<  | awk '{print "PW_"$$2 " " $$3 }' | tr '[:lower:]' '[:upper:]' | tr -- - _ | sed 's/^/#define /' >> $@
        @echo " " >> $@
-       @grep -- 'Auth-Type' $< | grep ^VALUE | awk '{print "PW_"$$2 "_" $$3 " " $$4 "  //!< AUTOGENERATED VALUE DEFINITION"}' | tr '[:lower:]' '[:upper:]' | tr -- - _ | sed 's/^/#define /' >> $@
+       @grep -- 'Auth-Type' $< | grep ^VALUE | awk '{print "PW_"$$2 "_" $$3 " " $$4 }' | tr '[:lower:]' '[:upper:]' | tr -- - _ | sed 's/^/#define /' >> $@
 
 src/include/%.h: share/dictionary.% share/dictionary.vqp
        @$(ECHO) HEADER $@
-       @grep ^ATTRIBUTE $<  | awk '{print "PW_"$$2 " " $$3 "   //!< AUTOGENERATED ATTRIBUTE DEFINITION"}' | tr '[:lower:]' '[:upper:]' | tr -- - _ | sed 's/^/#define /' > $@
-
-src/include/radius.h: | src/include/attributes.h $(RFC_HEADERS) src/include/vqp.h
-
-#
-#  So the headers are created before we compile anything
-#
-$(JLIBTOOL): src/include/radius.h
-
-src/freeradius-devel/features.h: src/include/features.h src/freeradius-devel
+       @echo "/* AUTO-GENERATED HEADER FILE.  DO NOT EDIT. */" > $@
+       @grep ^ATTRIBUTE $<  | awk '{print "PW_"$$2 " " $$3 } ' | tr '[:lower:]' '[:upper:]' | tr -- - _ | sed 's/^/#define /' >> $@
 
 #
 #  Build features.h by copying over WITH_* and RADIUSD_VERSION_*
@@ -97,8 +93,6 @@ src/include/features.h: src/include/features-h src/include/autoconf.h
        @grep "^#define[ ]*WITH_" src/include/autoconf.h >> $@
        @grep "^#define[ ]*RADIUSD_VERSION" src/include/autoconf.h >> $@
 
-src/freeradius-devel/missing.h: src/include/missing.h src/freeradius-devel
-
 #
 #  Use the SED script we built earlier to make permanent substitutions
 #  of definitions in missing-h to build missing.h
@@ -107,19 +101,25 @@ src/include/missing.h: src/include/missing-h src/include/autoconf.sed
        @$(ECHO) HEADER $@
        @sed -f src/include/autoconf.sed < $< > $@
 
-src/freeradius-devel/tls.h: src/include/tls.h src/freeradius-devel
-
 src/include/tls.h: src/include/tls-h src/include/autoconf.sed
        @$(ECHO) HEADER $@
        @sed -f src/include/autoconf.sed < $< > $@
 
-src/freeradius-devel/radpaths.h: src/include/radpaths.h src/freeradius-devel
-
 src/include/radpaths.h: src/include/build-radpaths-h
        @$(ECHO) HEADER $@
        @cd src/include && /bin/sh build-radpaths-h
 
-${BUILD_DIR}/make/jlibtool: $(HEADERS_DY)
+#
+#  Create the soft link for the fake include file path.
+#
+src/freeradius-devel:
+       @[ -e $@ ] || ln -s include $@
+
+#
+#  Ensure we set up the build environment
+#
+BOOTSTRAP_BUILD += src/freeradius-devel $(addprefix src/include/,$(HEADERS_DY)) $(HEADERS_RFC)
+scan: $(BOOTSTRAP_BUILD)
 
 ######################################################################
 #
@@ -138,10 +138,12 @@ $(SRC_INCLUDE_DIR):
 #  if there's a trailing slash, tries to create a directory
 #  it already created, and fails...
 #
-${SRC_INCLUDE_DIR}/%.h: ${top_srcdir}/src/include/%.h | $(SRC_INCLUDE_DIR)
+${SRC_INCLUDE_DIR}/%.h: src/include/%.h | $(SRC_INCLUDE_DIR)
        @echo INSTALL $(notdir $<)
        @$(INSTALL) -d -m 755 `echo $(dir $@) | sed 's/\/$$//'`
-       @sed 's/^#include <freeradius-devel/#include <freeradius/' < $< > $@
+# Expression must deal with indentation after the hash and copy it to the substitution string.
+# Hash not anchored to allow substitution in function documentation.
+       @sed -e 's/#\([\\t ]*\)include <freeradius-devel\/\([^>]*\)>/#\1include <freeradius\/\2>/g' < $< > $@
        @chmod 644 $@
 
 install.src.include: $(addprefix ${SRC_INCLUDE_DIR}/,${HEADERS})
@@ -152,7 +154,7 @@ install: install.src.include
 #
 .PHONY: clean.src.include distclean.src.include
 clean.src.include:
-       @rm -f $(HEADERS_DY)
+       @rm -f $(addprefix src/include/,$(HEADERS_DY)) $(HEADERS_RFC)
 
 clean: clean.src.include
 
index eab1227..a637c68 100644 (file)
@@ -54,6 +54,9 @@
 /* Define to 1 if you have the <sys/capability.h> header file. */
 #undef HAVE_CAPABILITY_H
 
+/* Define to 1 if you have the `clock_gettime' function. */
+#undef HAVE_CLOCK_GETTIME
+
 /* Define to 1 if you have the `closefrom' function. */
 #undef HAVE_CLOSEFROM
 
 /* Define to 1 if you have the <fnmatch.h> header file. */
 #undef HAVE_FNMATCH_H
 
+/* Define to 1 if you have the `fopencookie' function. */
+#undef HAVE_FOPENCOOKIE
+
+/* Define to 1 if you have the `funopen' function. */
+#undef HAVE_FUNOPEN
+
 /* Define to 1 if you have the `getaddrinfo' function. */
 #undef HAVE_GETADDRINFO
 
 /* Define if the function (or macro) htonlll exists. */
 #undef HAVE_HTONLLL
 
+/* Define to 1 if you have the `if_indextoname' function. */
+#undef HAVE_IF_INDEXTONAME
+
 /* define if you have IN6_PKTINFO (Linux) */
 #undef HAVE_IN6_PKTINFO
 
 /* Define to 1 if you have the `snprintf' function. */
 #undef HAVE_SNPRINTF
 
+/* Define to 1 if you have the `SSL_get_client_random' function. */
+#undef HAVE_SSL_GET_CLIENT_RANDOM
+
 /* Define to 1 if you have the <stdbool.h> header file. */
 #undef HAVE_STDBOOL_H
 
 /* Define to 1 if you have the <utmp.h> header file. */
 #undef HAVE_UTMP_H
 
+/* Define to 1 if you have the `vdprintf' function. */
+#undef HAVE_VDPRINTF
+
 /* Define to 1 if you have the `vsnprintf' function. */
 #undef HAVE_VSNPRINTF
 
index 2d80039..5da940c 100644 (file)
@@ -10,7 +10,7 @@
 #ifdef __cplusplus
 extern "C" {
 #endif
-#include <freeradius-devel/autoconf.h> /* Needed for endian macros */
+#include <freeradius-devel/autoconf.h> /* Needed for endian macros */
 
 /*
  *     The ubiquitous stringify macros
index 62d16b0..60c12b7 100644 (file)
@@ -139,6 +139,7 @@ typedef struct timeval _timeval_t;
 
 #define PW_TYPE_MULTI          (1 << 18) //!< CONF_PAIR can have multiple copies.
 #define PW_TYPE_NOT_EMPTY      (1 << 19) //!< CONF_PAIR is required to have a non zero length value.
+#define PW_TYPE_FILE_EXISTS    ((1 << 20) | PW_TYPE_STRING) //!< File matching value must exist
 /* @} **/
 
 #define FR_INTEGER_COND_CHECK(_name, _var, _cond, _new)\
index 48f46e1..a3c8f58 100644 (file)
@@ -205,7 +205,7 @@ extern const FR_NAME_NUMBER dict_attr_types[];
 extern const size_t dict_attr_sizes[PW_TYPE_MAX][2];
 extern const int fr_attr_max_tlv;
 extern const int fr_attr_shift[];
-extern const int fr_attr_mask[];
+extern const unsigned int fr_attr_mask[];
 
 /** dictionary attribute
  *
@@ -487,6 +487,7 @@ 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,
                                           unsigned int vendor);
+DICT_ATTR const *dict_parent(unsigned int attr, unsigned int vendor);
 int            dict_attr_child(DICT_ATTR const *parent,
                                unsigned int *pattr, unsigned int *pvendor);
 DICT_VALUE     *dict_valbyattr(unsigned int attr, unsigned int vendor, int val);
@@ -528,9 +529,9 @@ int         rad_pwdecode(char *encpw, size_t len, char const *secret,
                             uint8_t const *vector);
 
 #define        FR_TUNNEL_PW_ENC_LENGTH(_x) (2 + 1 + _x + PAD(_x + 1, 16))
-int            rad_tunnel_pwencode(char *encpw, size_t *len, char const *secret,
+ssize_t                rad_tunnel_pwencode(char *encpw, size_t *len, char const *secret,
                                    uint8_t const *vector);
-int            rad_tunnel_pwdecode(uint8_t *encpw, size_t *len,
+ssize_t                rad_tunnel_pwdecode(uint8_t *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);
@@ -696,13 +697,14 @@ extern uint32_t   fr_max_attributes; /* per incoming packet */
 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;
-void           rad_print_hex(RADIUS_PACKET *packet);
+void           rad_print_hex(RADIUS_PACKET const *packet);
 void           fr_printf_log(char const *, ...) CC_HINT(format (printf, 1, 2));
 
 /*
  *     Several handy miscellaneous functions.
  */
 int            fr_set_signal(int sig, sig_t func);
+int            fr_unset_signal(int sig);
 int            fr_link_talloc_ctx_free(TALLOC_CTX *parent, TALLOC_CTX *child);
 char const     *fr_inet_ntop(int af, void const *src);
 char const     *ip_ntoa(char *, uint32_t);
index b0960f6..9d59394 100644 (file)
@@ -351,6 +351,10 @@ size_t strlcat(char *dst, char const *src, size_t siz);
 struct tm *gmtime_r(time_t const *l_clock, struct tm *result);
 #endif
 
+#ifndef HAVE_VDPRINTF
+int vdprintf (int fd, char const *format, va_list args);
+#endif
+
 #ifndef HAVE_GETTIMEOFDAY
 int gettimeofday (struct timeval *tv, void *tz);
 #endif
index ac92777..7486ef1 100644 (file)
@@ -46,6 +46,8 @@ void add_to_modcallable(modcallable *parent, modcallable *this);
 
 void modcall_debug(modcallable *mc, int depth);
 
+int modcall_pass2_condition(fr_cond_t *c);
+
 #ifdef __cplusplus
 }
 #endif
index 12fa78d..44a2c13 100644 (file)
@@ -72,6 +72,11 @@ typedef enum {
 #define PW_RADIUS_TLS_PORT             2083
 #define PW_COA_UDP_PORT                        3799
 
+/*
+ *  The RFC says 4096 octets max, and most packets are less than 256.
+ */
+#define MAX_PACKET_LEN 4096
+
 #include <freeradius-devel/rfc2865.h>
 #include <freeradius-devel/rfc2866.h>
 #include <freeradius-devel/rfc2867.h>
@@ -110,6 +115,8 @@ typedef enum {
  */
 #include <freeradius-devel/attributes.h>
 
+#include <freeradius-devel/freeradius.h>
+
 #include <freeradius-devel/vqp.h>
 
 #define PW_DIGEST_RESPONSE             206
@@ -154,22 +161,22 @@ typedef enum {
 #define VENDORPEC_UKERNA               25622
 
 /*
- * Vendor specific attributes
- */
-#define PW_FREERADIUS_PROXIED_TO       1
-
-/*
  *     Microsoft has vendor code 311.
  */
-#define PW_MSCHAP_RESPONSE             1
-#define PW_MSCHAP_ERROR                        2
-#define PW_MSCHAP_CPW_1                        3
-#define PW_MSCHAP_CPW_2                        4
-#define PW_MSCHAP_NT_ENC_PW            6
-#define PW_MSCHAP_CHALLENGE            11
-#define PW_MSCHAP2_RESPONSE            25
-#define PW_MSCHAP2_SUCCESS             26
-#define PW_MSCHAP2_CPW                 27
+#define PW_MSCHAP_RESPONSE                     1
+#define PW_MSCHAP_ERROR                                2
+#define PW_MSCHAP_CPW_1                                3
+#define PW_MSCHAP_CPW_2                                4
+#define PW_MSCHAP_NT_ENC_PW                    6
+#define PW_MSCHAP_MPPE_ENCRYPTION_POLICY       7
+#define PW_MSCHAP_MPPE_ENCRYPTION_TYPES                8
+#define PW_MSCHAP_CHALLENGE                    11
+#define PW_MSCHAP_MPPE_SEND_KEY                        16
+#define PW_MSCHAP_MPPE_RECV_KEY                        17
+#define PW_MSCHAP2_RESPONSE                    25
+#define PW_MSCHAP2_SUCCESS                     26
+#define PW_MSCHAP2_CPW                         27
+#define PW_MS_QUARANTINE_SOH                   55
 
 /*
  * JANET's code for transporting eap channel binding data over ttls
index 1123b77..379d587 100644 (file)
@@ -167,6 +167,8 @@ typedef struct main_config {
 
        bool            write_pid;                      //!< write the PID file
 
+       bool            exiting;                        //!< are we exiting?
+
 
 #ifdef ENABLE_OPENSSL_VERSION_CHECK
        char const      *allow_vulnerable_openssl;      //!< The CVE number of the last security issue acknowledged.
@@ -222,6 +224,8 @@ struct rad_request {
 
        VALUE_PAIR              *config;        //!< #VALUE_PAIR (s) used to set per request parameters
                                                //!< for modules and the server core at runtime.
+
+       TALLOC_CTX              *state_ctx;     //!< for request->state
        VALUE_PAIR              *state;         //!< #VALUE_PAIR (s) available over the lifetime of the authentication
                                                //!< attempt. Useful where the attempt involves a sequence of
                                                //!< many request/challenge packets, like OTP, and EAP.
@@ -272,8 +276,6 @@ struct rad_request {
 #ifdef WITH_PROXY
        bool                    in_proxy_hash;
 
-       struct timeval          proxy_retransmit;
-
        uint32_t                num_proxied_requests;   //!< How many times this request was proxied.
                                                        //!< Retransmissions are driven by requests from the NAS.
        uint32_t                num_proxied_responses;
@@ -342,7 +344,6 @@ typedef enum request_fail {
  *
  *     We really shouldn't have this many.
  */
-extern char const      *progname;
 extern log_lvl_t       rad_debug_lvl;
 extern char const      *radacct_dir;
 extern char const      *radlog_dir;
index 4548b7b..e36d81d 100644 (file)
@@ -68,14 +68,20 @@ static inline _t __fr_thread_local_init_##_n(pthread_destructor_t func)\
 static pthread_key_t __fr_thread_local_key_##_n;\
 static pthread_once_t __fr_thread_local_once_##_n = PTHREAD_ONCE_INIT;\
 static pthread_destructor_t __fr_thread_local_destructor_##_n = NULL;\
-static inline void __fr_thread_local_key_init_##_n(void)\
+static void __fr_thread_local_destroy_##_n(UNUSED void *unused)\
 {\
-       (void) pthread_key_create(&__fr_thread_local_key_##_n, __fr_thread_local_destructor_##_n);\
+       __fr_thread_local_destructor_##_n(_n);\
 }\
-static inline _t __fr_thread_local_init_##_n(pthread_destructor_t func)\
+static void __fr_thread_local_key_init_##_n(void)\
+{\
+       (void) pthread_key_create(&__fr_thread_local_key_##_n, __fr_thread_local_destroy_##_n);\
+}\
+static _t __fr_thread_local_init_##_n(pthread_destructor_t func)\
 {\
        __fr_thread_local_destructor_##_n = func;\
+       if (_n) return _n; \
        (void) pthread_once(&__fr_thread_local_once_##_n, __fr_thread_local_key_init_##_n);\
+       (void) pthread_setspecific(__fr_thread_local_key_##_n, &(_n));\
        return _n;\
 }
 #  define fr_thread_local_init(_n, _f) __fr_thread_local_init_##_n(_f)
@@ -86,26 +92,22 @@ static inline _t __fr_thread_local_init_##_n(pthread_destructor_t func)\
 #  define fr_thread_local_setup(_t, _n) \
 static pthread_key_t __fr_thread_local_key_##_n;\
 static pthread_once_t __fr_thread_local_once_##_n = PTHREAD_ONCE_INIT;\
-static pthread_destructor_t __fr_thread_local_destructor_##_n = NULL; \
-static inline void __fr_thread_local_key_init_##_n(void)\
-{\
-       (void) pthread_key_create(&__fr_thread_local_key_##_n, __fr_thread_local_destructor_##_n);\
-}\
-static inline _t __fr_thread_local_init_##_n(pthread_destructor_t func)\
+static pthread_destructor_t __fr_thread_local_destructor_##_n = NULL;\
+static void __fr_thread_local_destroy_##_n(UNUSED void *unused)\
 {\
-       __fr_thread_local_destructor_##_n = func;\
-       (void) pthread_once(&__fr_thread_local_once_##_n, __fr_thread_local_key_init_##_n);\
-       return pthread_getspecific(__fr_thread_local_key_##_n);\
+       __fr_thread_local_destructor_##_n(_n);\
 }\
-DIAG_OFF(unused-function)\
-static inline _t __fr_thread_local_get_##_n(void)\
+static void __fr_thread_local_key_init_##_n(void)\
 {\
-       return pthread_getspecific(__fr_thread_local_key_##_n);\
+       (void) pthread_key_create(&__fr_thread_local_key_##_n, __fr_thread_local_destroy_##_n);\
+       (void) pthread_setspecific(__fr_thread_local_key_##_n, &(_n));\
 }\
-DIAG_ON(unused-function)\
-static inline int __fr_thread_local_set_##_n(_t val)\
+static _t __fr_thread_local_init_##_n(pthread_destructor_t func)\
 {\
-       return pthread_setspecific(__fr_thread_local_key_##_n, val);\
+       __fr_thread_local_destructor_##_n = func;\
+       if (_n) return _n; \
+       (void) pthread_once(&__fr_thread_local_once_##_n, __fr_thread_local_key_init_##_n);\
+       return _n;\
 }
 #  define fr_thread_local_init(_n, _f)                 __fr_thread_local_init_##_n(_f)
 #  define fr_thread_local_set(_n, _v)                  __fr_thread_local_set_##_n(_v)
index a41c6f5..9142b91 100644 (file)
@@ -106,6 +106,12 @@ typedef struct _tls_info_t {
        int             version;
 } tls_info_t;
 
+#if OPENSSL_VERSION_NUMBER < 0x10001000L
+#define ssl_session ssl->session
+#else
+#define ssl_session session
+#endif
+
 /** Contains EAP-REQUEST specific data (ie FR_TLS_DATA(fragment), EAPTLS-ALERT, EAPTLS-REQUEST ...)
  *
  * The tls_session_t Structure gets stored as opaque in eap_handler_t
@@ -113,6 +119,9 @@ typedef struct _tls_info_t {
 typedef struct _tls_session_t {
        SSL_CTX         *ctx;
        SSL             *ssl;
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+       SSL_SESSION     *session;
+#endif
        tls_info_t      info;
 
        BIO             *into_ssl;
@@ -289,6 +298,11 @@ void               tls_global_init(void);
 #ifdef ENABLE_OPENSSL_VERSION_CHECK
 int            tls_global_version_check(char const *acknowledged);
 #endif
+
+int            tls_error_log(REQUEST *request, char const *msg, ...) CC_HINT(format (printf, 2, 3));
+int            tls_error_io_log(REQUEST *request, tls_session_t *session, int ret, char const *msg, ...)
+                                CC_HINT(format (printf, 4, 5));
+
 void           tls_global_cleanup(void);
 tls_session_t  *tls_new_session(TALLOC_CTX *ctx, fr_tls_server_conf_t *conf, REQUEST *request, bool client_cert);
 tls_session_t  *tls_new_client_session(TALLOC_CTX *ctx, fr_tls_server_conf_t *conf, int fd);
@@ -298,6 +312,7 @@ SSL_CTX             *tls_init_ctx(fr_tls_server_conf_t *conf, int client);
 int            tls_handshake_recv(REQUEST *, tls_session_t *ssn);
 int            tls_handshake_send(REQUEST *, tls_session_t *ssn);
 void           tls_session_information(tls_session_t *ssn);
+void           tls_session_id(SSL_SESSION *ssn, char *buffer, size_t bufsize);
 
 /*
  *     Low-level TLS stuff
@@ -331,19 +346,17 @@ struct fr_tls_server_conf_t {
        char const      *ca_file;
        char const      *dh_file;
        char const      *rsa_file;
-       bool            rsa_key;
-       bool            dh_key;
-       uint32_t        rsa_key_length;
-       uint32_t        dh_key_length;
        uint32_t        verify_depth;
        bool            file_type;
        bool            include_length;
+       bool            auto_chain;
+       bool            disable_single_dh_use;
        bool            disable_tlsv1;
        bool            disable_tlsv1_1;
        bool            disable_tlsv1_2;
 
        /*
-        *      Always < 4096 (due to radius limit), 0 by default = 2048
+        *      Always < 4096 (due to radius limit), 0 by default = 1024
         */
        uint32_t        fragment_size;
        bool            check_crl;
@@ -361,6 +374,7 @@ struct fr_tls_server_conf_t {
        char            session_context_id[SSL_MAX_SSL_SESSION_ID_LENGTH];
        time_t          session_last_flushed;
 
+       bool            verify_skip_if_ocsp_ok;
        char const      *verify_tmp_dir;
        char const      *verify_client_cert_cmd;
        bool            require_client_cert;
index 89cf34c..ae88ebe 100644 (file)
@@ -392,6 +392,7 @@ VALUE_PAIR *fr_cursor_remove(vp_cursor_t *cursor)
                *(cursor->first) = vp->next;
                cursor->current = vp->next;
                cursor->next = vp->next ? vp->next->next : NULL;
+               before = NULL;
                goto fixup;
        }
 
@@ -413,9 +414,10 @@ fixup:
        vp->next = NULL;                        /* limit scope of fr_pair_list_free() */
 
        /*
-        *      Fixup cursor->found if we removed the VP it was referring to
+        *      Fixup cursor->found if we removed the VP it was referring to,
+        *      and point to the previous one.
         */
-       if (vp == cursor->found) cursor->found = cursor->current;
+       if (vp == cursor->found) cursor->found = before;
 
        /*
         *      Fixup cursor->last if we removed the VP it was referring to
index a56e4ec..2a034a4 100644 (file)
@@ -703,11 +703,11 @@ NEVER_RETURNS void fr_fault(int sig)
        if (strlen(p) >= left) goto oob;
        strlcpy(out, p, left);
 
-       FR_FAULT_LOG("Calling: %s", cmd);
-
        {
                bool disable = false;
 
+               FR_FAULT_LOG("Calling: %s", cmd);
+
                /*
                 *      Here we temporarily enable the dumpable flag so if GBD or LLDB
                 *      is called in the panic_action, they can pattach to the running
@@ -737,12 +737,24 @@ NEVER_RETURNS void fr_fault(int sig)
                                fr_exit_now(1);
                        }
                }
+
+               FR_FAULT_LOG("Panic action exited with %i", code);
+
+               fr_exit_now(code);
        }
 
-       FR_FAULT_LOG("Panic action exited with %i", code);
 
 finish:
-       fr_exit_now(1);
+       /*
+        *      (Re-)Raise the signal, so that if we're running under
+        *      a debugger, the debugger can break when it receives
+        *      the signal.
+        */
+       fr_unset_signal(sig);   /* Make sure we don't get into a loop */
+
+       raise(sig);
+
+       fr_exit_now(1);         /* Function marked as noreturn */
 }
 
 /** Callback executed on fatal talloc error
@@ -926,7 +938,7 @@ int fr_fault_setup(char const *cmd, char const *program)
                env = getenv("DEBUG");
                if (!env || (strcmp(env, "no") == 0)) {
                        debug_state = DEBUG_STATE_NOT_ATTACHED;
-               } else if (strcmp(env, "auto") == 0) {
+               } else if (!strcmp(env, "auto") || !strcmp(env, "yes")) {
                        /*
                         *  Figure out if we were started under a debugger
                         */
index 03de2b3..5b44f77 100644 (file)
@@ -160,7 +160,7 @@ const size_t dict_attr_sizes[PW_TYPE_MAX][2] = {
 int const fr_attr_max_tlv = MAX_TLV_NEST;
 int const fr_attr_shift[MAX_TLV_NEST + 1] = { 0, 8, 16, 24, 29 };
 
-int const fr_attr_mask[MAX_TLV_NEST + 1] = { 0xff, 0xff, 0xff, 0x1f, 0x07 };
+unsigned const fr_attr_mask[MAX_TLV_NEST + 1] = { 0xff, 0xff, 0xff, 0x1f, 0x07 };
 
 /*
  *     attr & fr_attr_parent_mask[i] == Nth parent of attr
@@ -641,17 +641,27 @@ int dict_valid_name(char const *name)
 
 
 /*
- *     Bamboo skewers under the fingernails in 5, 4, 3, 2, ...
+ *     Find the parent of the attr/vendor.
  */
-static DICT_ATTR const *dict_parent(unsigned int attr, unsigned int vendor)
+DICT_ATTR const *dict_parent(unsigned int attr, unsigned int vendor)
 {
        int i;
        unsigned int base_vendor;
 
        /*
-        *      RFC attributes can't be of type "tlv".
+        *      RFC attributes can't be of type "tlv", except for dictionary.rfc6930
         */
-       if (!vendor) return NULL;
+       if (!vendor) {
+#ifdef PW_IPV6_6RD_CONFIGURATION
+               if (attr == PW_IPV6_6RD_CONFIGURATION) return NULL;
+
+               if (((attr & 0xff) == PW_IPV6_6RD_CONFIGURATION) &&
+                   (attr >> 8) < 4) {
+                       return dict_attrbyvalue(PW_IPV6_6RD_CONFIGURATION, 0);
+               }
+#endif
+               return NULL;
+       }
 
        base_vendor = vendor & (FR_MAX_VENDOR - 1);
 
@@ -829,7 +839,7 @@ int dict_addattr(char const *name, int attr, unsigned int vendor, PW_TYPE type,
 #ifdef WITH_DHCP
                    || flags.array
 #endif
-                   || (flags.encrypt != FLAG_ENCRYPT_NONE)) {
+                   || ((flags.encrypt != FLAG_ENCRYPT_NONE) && (flags.encrypt != FLAG_ENCRYPT_TUNNEL_PASSWORD))) {
                        fr_strerror_printf("dict_addattr: The \"extended\" attributes MUST NOT have any flags set");
                        return -1;
                }
@@ -1350,6 +1360,8 @@ static int sscanf_i(char const *str, unsigned int *pvalue)
  *
  *     Remember, the packing format is weird.
  *
+ *     Vendor  Attribute
+ *     ------  ---------
  *     00VID   000000AA        normal VSA for vendor VID
  *     00VID   AABBCCDD        normal VSAs with TLVs
  *     EE000   000000AA        extended attr (241.1)
@@ -1363,8 +1375,12 @@ int dict_str2oid(char const *ptr, unsigned int *pvalue, unsigned int *pvendor,
                 int tlv_depth)
 {
        char const *p;
-       unsigned int value;
-       DICT_ATTR const *da = NULL;
+       unsigned int attr;
+       
+#ifdef WITH_DICT_OID_DEBUG
+       fprintf(stderr, "PARSING %s tlv_depth %d pvalue %08x pvendor %08x\n", ptr,
+               tlv_depth, *pvalue, *pvendor);
+#endif
 
        if (tlv_depth > fr_attr_max_tlv) {
                fr_strerror_printf("Too many sub-attributes");
@@ -1372,103 +1388,197 @@ int dict_str2oid(char const *ptr, unsigned int *pvalue, unsigned int *pvendor,
        }
 
        /*
-        *      If *pvalue is set, check if the attribute exists.
-        *      Otherwise, check that the vendor exists.
+        *      No vendor, try to do basic parsing.
         */
-       if (*pvalue) {
-               da = dict_attrbyvalue(*pvalue, *pvendor);
-               if (!da) {
-                       fr_strerror_printf("Parent attribute is undefined");
+       if (!*pvendor && !*pvalue) {
+               /*
+                *      Can't call us with a pre-parsed value and no vendor.
+                */
+               if (tlv_depth != 0) {
+                       fr_strerror_printf("Invalid call with wrong TLV depth %d", tlv_depth);
                        return -1;
                }
 
-               if (!da->flags.has_tlv && !da->flags.extended) {
-                       fr_strerror_printf("Parent attribute %s cannot have sub-attributes",
-                                          da->name);
+               p = strchr(ptr, '.');
+               if (!sscanf_i(ptr, &attr)) {
+                       fr_strerror_printf("Invalid data '%s' in attribute identifier", ptr);
                        return -1;
                }
 
-       } else if ((*pvendor & (FR_MAX_VENDOR - 1)) != 0) {
-               if (!dict_vendorbyvalue(*pvendor & (FR_MAX_VENDOR - 1))) {
-                       fr_strerror_printf("Unknown vendor %u",
-                                          *pvendor & (FR_MAX_VENDOR - 1));
-                       return -1;
+               /*
+                *      Normal attribute with no OID.  Return it.
+                */
+               if (!p) {
+                       *pvalue = attr;
+                       goto done;
                }
-       }
-
-       p = strchr(ptr, '.');
 
-       /*
-        *      Look for 26.VID.x.y
-        *
-        *      If we find it, re-write the parameters, and recurse.
-        */
-       if (!*pvendor && (tlv_depth == 0) && (*pvalue == PW_VENDOR_SPECIFIC)) {
-               DICT_VENDOR const *dv;
+               /*
+                *      We have an OID, look up the attribute to see what it is.
+                */
+               if (attr != PW_VENDOR_SPECIFIC) {
+                       DICT_ATTR const *da;
 
-               if (!p) {
-                       fr_strerror_printf("VSA needs to have sub-attribute");
-                       return -1;
-               }
+                       da = dict_attrbyvalue(attr, 0);
+                       if (!da) {
+                               *pvalue = attr;
+                               goto done;
+                       }
 
-               if (!sscanf_i(ptr, pvendor)) {
-                       fr_strerror_printf("Invalid number in attribute");
-                       return -1;
-               }
+                       /*
+                        *      Standard attributes (including internal
+                        *      ones) can have TLVs, but only for some
+                        *      of them.
+                        */
+                       if (!da->flags.extended) {
+#ifdef PW_IPV6_6RD_CONFIGURATION
+                               if (attr == PW_IPV6_6RD_CONFIGURATION) {
+                                       *pvalue = attr;
+                                       ptr = p + 1;
+                                       tlv_depth = 1;
+                                       goto keep_parsing;
+                               }
+#endif
+                               fr_strerror_printf("Standard attributes cannot use OIDs");
+                               return -1;
+                       }
 
-               if (*pvendor >= FR_MAX_VENDOR) {
-                       fr_strerror_printf("Cannot handle vendor ID larger than 2^24");
+                       *pvendor = attr * FR_MAX_VENDOR;
+                       ptr = p + 1;
+               } /* and fall through to re-parsing the VSA */
 
+               /*
+                *      Look for the attribute number.
+                */
+               if (!sscanf_i(ptr, &attr)) {
+                       fr_strerror_printf("Invalid data '%s' in attribute identifier", ptr);
                        return -1;
                }
 
-               dv = dict_vendorbyvalue(*pvendor & (FR_MAX_VENDOR - 1));
-               if (!dv) {
-                       fr_strerror_printf("Unknown vendor \"%u\" ",
-                                          *pvendor  & (FR_MAX_VENDOR - 1));
-                       return -1;
-               }
+               p = strchr(ptr, '.');
 
                /*
-                *      Start off with (attr=0, vendor=VID), and
-                *      recurse.  This causes the various checks above
-                *      to be done.
+                *      Handle VSAs.  Either in the normal space, or in the extended space.
                 */
-               *pvalue = 0;
-               return dict_str2oid(p + 1, pvalue, pvendor, 0);
-       }
+               if (attr == PW_VENDOR_SPECIFIC) {
+                       if (!p) {
+                               *pvalue = attr;
+                               goto done;
+                       }
+                       ptr = p + 1;
 
-       if (!sscanf_i(ptr, &value)) {
-               fr_strerror_printf("Invalid number in attribute");
-               return -1;
-       }
+                       if (!sscanf_i(ptr, &attr)) {
+                               fr_strerror_printf("Invalid data '%s' in vendor identifier", ptr);
+                               return -1;
+                       }
+
+                       p = strchr(ptr, '.');
+                       if (!p) {
+                               fr_strerror_printf("Cannot define VENDOR in an ATTRIBUTE");
+                               return -1;
+                       }
+                       ptr = p + 1;
+
+                       *pvendor |= attr;
+               } else {
+                       *pvalue = attr;
+               }
+       } /* fall through to processing an OID with pre-defined *pvendor and *pvalue */
+
+keep_parsing:
+#ifdef WITH_DICT_OID_DEBUG
+       fprintf(stderr, "KEEP PARSING %s tlv_depth %d pvalue %08x pvendor %08x\n", ptr,
+               tlv_depth, *pvalue, *pvendor);
+#endif
+
+       /*
+        *      Check the vendor.  Only RFC format attributes can have TLVs.
+        */
+       if (*pvendor) {
+               DICT_VENDOR const *dv = NULL;
 
-       if (!*pvendor && (tlv_depth == 1) && da &&
-           (da->flags.has_tlv || da->flags.extended)) {
+               dv = dict_vendorbyvalue(*pvendor);
+               if (dv && (dv->type != 1)) {
+                       if (*pvalue || (tlv_depth != 0)) {
+                               fr_strerror_printf("Attribute cannot have TLVs");
+                               return -1;
+                       }
 
+                       if (!sscanf_i(ptr, &attr)) {
+                               fr_strerror_printf("Invalid data '%s' in attribute identifier", ptr);
+                               return -1;
+                       }
 
-               *pvendor = *pvalue * FR_MAX_VENDOR;
-               *pvalue = value;
+                       if ((dv->type < 3) && (attr > (unsigned int) (1 << (8 * dv->type)))) {
+                               fr_strerror_printf("Number '%s' out of allowed range in attribute identifier", ptr);
+                               return -1;
+                       }
+                       
+                       *pvalue = attr;
 
-               if (!p) return 0;
-               return dict_str2oid(p + 1, pvalue, pvendor, 1);
+#ifdef WITH_DHCP
+                       /*
+                        *      DHCP attributes can have TLVs. <sigh>
+                        */
+                       if (*pvendor == 54) goto dhcp_skip;
+#endif
+                       goto done;
+               }
        }
 
        /*
-        *      And pack the data according to the scheme described in
-        *      the comments at the start of this function.
+        *      Parse the rest of the TLVs.
         */
-       if (*pvalue) {
-               *pvalue |= (value & fr_attr_mask[tlv_depth]) << fr_attr_shift[tlv_depth];
-       } else {
-               *pvalue = value;
-       }
+       while (tlv_depth <= fr_attr_max_tlv) {
+#ifdef WITH_DICT_OID_DEBUG
+               fprintf(stderr, "TLV  PARSING %s tlv_depth %d pvalue %08x pvendor %08x\n", ptr,
+                       tlv_depth, *pvalue, *pvendor);
+#endif
 
-       if (p) {
-               return dict_str2oid(p + 1, pvalue, pvendor, tlv_depth + 1);
+               if (!sscanf_i(ptr, &attr)) {
+                       fr_strerror_printf("Invalid data '%s' in attribute identifier", ptr);
+                       return -1;
+               }
+
+               if (attr > fr_attr_mask[tlv_depth]) {
+                       fr_strerror_printf("Number '%s' out of allowed range in attribute identifier", ptr);
+                       return -1;
+               }
+
+               attr <<= fr_attr_shift[tlv_depth];
+
+#ifdef WITH_DICT_OID_DEBUG
+               if (*pvendor) {
+                       DICT_ATTR const *da;
+
+                       da = dict_parent(*pvalue | attr, *pvendor);
+                       if (!da) {
+                               fprintf(stderr, "STR2OID FAILED PARENT %08x | %08x, %08x\n",
+                                       *pvalue, attr, *pvendor);
+                       } else if ((da->attr != *pvalue) || (da->vendor != *pvendor)) {
+                               fprintf(stderr, "STR2OID DISAGREEMENT WITH PARENT %08x, %08x\t%08x, %08x\n",
+                                       *pvalue, *pvendor, da->attr, da->vendor);
+                       }
+               }
+#endif
+
+               *pvalue |= attr;
+
+#ifdef WITH_DHCP
+       dhcp_skip:
+#endif
+               p = strchr(ptr, '.');
+               if (!p) break;
+
+               ptr = p + 1;
+               tlv_depth++;
        }
 
-       return tlv_depth;
+done:
+#ifdef WITH_DICT_OID_DEBUG
+       fprintf(stderr, "RETURNING %08x %08x\n", *pvalue, *pvendor);
+#endif
+       return 0;
 }
 
 
@@ -1497,7 +1607,7 @@ static int process_attribute(char const* fn, int const line,
        /*
         *      Dictionaries need to have real names, not shitty ones.
         */
-       if (strncmp(argv[1], "Attr-", 5) == 0) {
+       if (strncmp(argv[0], "Attr-", 5) == 0) {
                fr_strerror_printf("dict_init: %s[%d]: Invalid attribute name",
                                   fn, line);
                return -1;
@@ -1508,26 +1618,23 @@ static int process_attribute(char const* fn, int const line,
        /*
         *      Look for OIDs before doing anything else.
         */
-       p = strchr(argv[1], '.');
-       if (p) oid = 1;
-
-       /*
-        *      Validate all entries
-        */
-       if (!sscanf_i(argv[1], &value)) {
-               fr_strerror_printf("dict_init: %s[%d]: invalid value", fn, line);
-               return -1;
-       }
+       if (strchr(argv[1], '.') != NULL) oid = 1;
 
-       if (oid) {
+       {
                DICT_ATTR const *da;
 
                vendor = block_vendor;
 
+               if (!block_tlv) {
+                       value = 0;
+               } else {
+                       value = block_tlv->attr;
+               }
+
                /*
-                *      Parse the rest of the OID.
+                *      Parse OID.
                 */
-               if (dict_str2oid(p + 1, &value, &vendor, tlv_depth + 1) < 0) {
+               if (dict_str2oid(argv[1], &value, &vendor, tlv_depth) < 0) {
                        char buffer[256];
 
                        strlcpy(buffer, fr_strerror(), sizeof(buffer));
@@ -1537,19 +1644,21 @@ static int process_attribute(char const* fn, int const line,
                }
                block_vendor = vendor;
 
-               /*
-                *      Set the flags based on the parents flags.
-                */
-               da = dict_parent(value, vendor);
-               if (!da) {
-                       fr_strerror_printf("dict_init: %s[%d]: Parent attribute is undefined.", fn, line);
-                       return -1;
-               }
+               if (oid) {
+                       /*
+                        *      Set the flags based on the parents flags.
+                        */
+                       da = dict_parent(value, vendor);
+                       if (!da) {
+                               fr_strerror_printf("dict_init: %s[%d]: Parent attribute for %08x,%08x is undefined.", fn, line, value, vendor);
+                               return -1;
+                       }
 
-               flags.extended = da->flags.extended;
-               flags.long_extended = da->flags.long_extended;
-               flags.evs = da->flags.evs;
-               if (da->flags.has_tlv) flags.is_tlv = 1;
+                       flags.extended = da->flags.extended;
+                       flags.long_extended = da->flags.long_extended;
+                       flags.evs = da->flags.evs;
+                       if (da->flags.has_tlv) flags.is_tlv = 1;
+               }
        }
 
        if (strncmp(argv[2], "octets[", 7) != 0) {
@@ -1574,7 +1683,7 @@ static int process_attribute(char const* fn, int const line,
 
                *p = 0;
 
-               if (!sscanf_i(argv[1], &length)) {
+               if (!sscanf_i(argv[2] + 7, &length)) {
                        fr_strerror_printf("dict_init: %s[%d]: invalid length", fn, line);
                        return -1;
                }
@@ -2853,15 +2962,11 @@ DICT_ATTR const *dict_unknown_afrom_fields(TALLOC_CTX *ctx, unsigned int attr, u
  */
 int dict_unknown_from_str(DICT_ATTR *da, char const *name)
 {
-       unsigned int    attr, vendor = 0;
-       unsigned int    dv_type = 1;    /* The type of vendor field */
+       unsigned int    attr = 0, vendor = 0;
 
        char const      *p = name;
        char            *q;
 
-       DICT_VENDOR     *dv;
-       DICT_ATTR const *found;
-
        if (dict_valid_name(name) < 0) return -1;
 
        /*
@@ -2925,127 +3030,10 @@ int dict_unknown_from_str(DICT_ATTR *da, char const *name)
                return -1;
        }
 
-       attr = strtol(p + 5, &q, 10);
-
-       /*
-        *      Invalid name.
-        */
-       if (attr == 0) {
-               fr_strerror_printf("Invalid value in attribute name \"%s\"", name);
-
-               return -1;
-       }
-
-       p = q;
-
-       /*
-        *      Vendor-%d-Attr-%d
-        *      VendorName-Attr-%d
-        *      Attr-%d
-        *      Attr-%d.
-        *
-        *      Anything else is invalid.
-        */
-       if (((vendor != 0) && (*p != '\0')) ||
-           ((vendor == 0) && *p && (*p != '.'))) {
-       invalid:
-               fr_strerror_printf("Invalid OID");
-               return -1;
-       }
-
        /*
-        *      Look for OIDs.  Require the "Attr-26.Vendor-Id.type"
-        *      format, and disallow "Vendor-%d-Attr-%d" and
-        *      "VendorName-Attr-%d"
-        *
-        *      This section parses the Vendor-Id portion of
-        *      Attr-%d.%d.  where the first number is 26, *or* an
-        *      extended name of the "evs" foundta type.
+        *      Parse the OID, with a (possibly) pre-defined vendor.
         */
-       if (*p == '.') {
-               found = dict_attrbyvalue(attr, 0);
-               if (!found) {
-                       fr_strerror_printf("Cannot parse names without dictionaries");
-
-                       return -1;
-               }
-
-               if ((attr != PW_VENDOR_SPECIFIC) &&
-                   !(found->flags.extended || found->flags.long_extended)) {
-                       fr_strerror_printf("Standard attributes cannot use OIDs");
-
-                       return -1;
-               }
-
-               if ((attr == PW_VENDOR_SPECIFIC) || found->flags.evs) {
-                       vendor = strtol(p + 1, &q, 10);
-                       if ((vendor == 0) || (vendor > FR_MAX_VENDOR)) {
-                               fr_strerror_printf("Invalid vendor");
-
-                               return -1;
-                       }
-
-                       if (*q != '.') goto invalid;
-
-                       p = q;
-
-                       if (found->flags.evs) vendor |= attr * FR_MAX_VENDOR;
-                       attr = 0;
-               } /* else the second number is a TLV number */
-       }
-
-       /*
-        *      Get the expected maximum size of the name.
-        */
-       if (vendor) {
-               dv = dict_vendorbyvalue(vendor & (FR_MAX_VENDOR - 1));
-               if (dv) {
-                       dv_type = dv->type;
-                       if (dv_type > 3) dv_type = 3; /* hack */
-               }
-       }
-
-       /*
-        *      Parse the next number.  It could be a Vendor-Type
-        *      of 1..2^24, or it could be a TLV.
-        */
-       if (*p == '.') {
-               attr = strtol(p + 1, &q, 10);
-               if (attr == 0) {
-                       fr_strerror_printf("Invalid name number");
-                       return -1;
-               }
-
-               if (*q) {
-                       if (*q != '.') {
-                               goto invalid;
-                       }
-
-                       if (dv_type != 1) {
-                               goto invalid;
-                       }
-               }
-
-               p = q;
-       }
-
-       /*
-        *      Enforce a maximum value on the attribute number.
-        */
-       if ((vendor > 0) && (attr >= (unsigned) (1 << (dv_type << 3)))) goto invalid;
-
-       if (*p == '.') {
-               if (dict_str2oid(p + 1, &attr, &vendor, 1) < 0) {
-                       return -1;
-               }
-       }
-
-       /*
-        *      If the caller doesn't provide a DICT_ATTR
-        *      we can't call dict_unknown_from_fields.
-        */
-       if (!da) {
-               fr_strerror_printf("Unknown attributes disallowed");
+       if (dict_str2oid(p + 5, &attr, &vendor, 0) < 0) {
                return -1;
        }
 
index 813e1ae..e9c8617 100644 (file)
@@ -37,6 +37,113 @@ RCSID("$Id$")
 fr_thread_local_setup(char *, fr_strerror_buffer)      /* macro */
 fr_thread_local_setup(char *, fr_syserror_buffer)      /* macro */
 
+#ifndef NDEBUG
+/** POSIX-2008 errno macros
+ *
+ * Non-POSIX macros may be added, but you must check they're defined.
+ */
+char const *fr_errno_macro_names[] = {
+       [E2BIG] = "E2BIG",
+       [EACCES] = "EACCES",
+       [EADDRINUSE] = "EADDRINUSE",
+       [EADDRNOTAVAIL] = "EADDRNOTAVAIL",
+       [EAFNOSUPPORT] = "EAFNOSUPPORT",
+#if EWOULDBLOCK == EAGAIN
+       [EWOULDBLOCK] = "EWOULDBLOCK or EAGAIN",
+#else
+       [EAGAIN] = "EAGAIN",
+       [EWOULDBLOCK] = "EWOULDBLOCK",
+#endif
+       [EALREADY] = "EALREADY",
+       [EBADF] = "EBADF",
+       [EBADMSG] = "EBADMSG",
+       [EBUSY] = "EBUSY",
+       [ECANCELED] = "ECANCELED",
+       [ECHILD] = "ECHILD",
+       [ECONNABORTED] = "ECONNABORTED",
+       [ECONNREFUSED] = "ECONNREFUSED",
+       [ECONNRESET] = "ECONNRESET",
+       [EDEADLK] = "EDEADLK",
+       [EDESTADDRREQ] = "EDESTADDRREQ",
+       [EDOM] = "EDOM",
+       [EDQUOT] = "EDQUOT",
+       [EEXIST] = "EEXIST",
+       [EFAULT] = "EFAULT",
+       [EFBIG] = "EFBIG",
+       [EHOSTUNREACH] = "EHOSTUNREACH",
+       [EIDRM] = "EIDRM",
+       [EILSEQ] = "EILSEQ",
+       [EINPROGRESS] = "EINPROGRESS",
+       [EINTR] = "EINTR",
+       [EINVAL] = "EINVAL",
+       [EIO] = "EIO",
+       [EISCONN] = "EISCONN",
+       [EISDIR] = "EISDIR",
+       [ELOOP] = "ELOOP",
+       [EMFILE] = "EMFILE",
+       [EMLINK] = "EMLINK",
+       [EMSGSIZE] = "EMSGSIZE",
+       [EMULTIHOP] = "EMULTIHOP",
+       [ENAMETOOLONG] = "ENAMETOOLONG",
+       [ENETDOWN] = "ENETDOWN",
+       [ENETRESET] = "ENETRESET",
+       [ENETUNREACH] = "ENETUNREACH",
+       [ENFILE] = "ENFILE",
+       [ENOBUFS] = "ENOBUFS",
+#ifdef ENODATA
+       [ENODATA] = "ENODATA",
+#endif
+       [ENODEV] = "ENODEV",
+       [ENOENT] = "ENOENT",
+       [ENOEXEC] = "ENOEXEC",
+       [ENOLCK] = "ENOLCK",
+       [ENOLINK] = "ENOLINK",
+       [ENOMEM] = "ENOMEM",
+       [ENOMSG] = "ENOMSG",
+       [ENOPROTOOPT] = "ENOPROTOOPT",
+       [ENOSPC] = "ENOSPC",
+#ifdef ENOSR
+       [ENOSR] = "ENOSR",
+#endif
+#ifdef ENOSTR
+       [ENOSTR] = "ENOSTR",
+#endif
+       [ENOSYS] = "ENOSYS",
+       [ENOTCONN] = "ENOTCONN",
+       [ENOTDIR] = "ENOTDIR",
+       [ENOTEMPTY] = "ENOTEMPTY",
+#ifdef ENOTRECOVERABLE
+       [ENOTRECOVERABLE] = "ENOTRECOVERABLE",
+#endif
+       [ENOTSOCK] = "ENOTSOCK",
+       [ENOTSUP] = "ENOTSUP",
+#if ENOTSUP != EOPNOTSUPP
+       [EOPNOTSUPP] = "EOPNOTSUPP",
+#endif
+       [ENOTTY] = "ENOTTY",
+       [ENXIO] = "ENXIO",
+       [EOVERFLOW] = "EOVERFLOW",
+#ifdef EOWNERDEAD
+       [EOWNERDEAD] = "EOWNERDEAD",
+#endif
+       [EPERM] = "EPERM",
+       [EPIPE] = "EPIPE",
+       [EPROTO] = "EPROTO",
+       [EPROTONOSUPPORT] = "EPROTONOSUPPORT",
+       [EPROTOTYPE] = "EPROTOTYPE",
+       [ERANGE] = "ERANGE",
+       [EROFS] = "EROFS",
+       [ESPIPE] = "ESPIPE",
+       [ESRCH] = "ESRCH",
+       [ESTALE] = "ESTALE",
+#ifdef ETIME
+       [ETIME] = "ETIME",
+#endif
+       [ETIMEDOUT] = "ETIMEDOUT",
+       [ETXTBSY] = "ETXTBSY",
+       [EXDEV] = "EXDEV"
+};
+#endif
 
 /*
  *     Explicitly cleanup the memory allocated to the error buffer,
@@ -140,7 +247,7 @@ char const *fr_strerror(void)
  */
 char const *fr_syserror(int num)
 {
-       char *buffer;
+       char *buffer, *p, *end;
        int ret;
 
        buffer = fr_thread_local_init(fr_syserror_buffer, _fr_logging_free);
@@ -162,15 +269,30 @@ char const *fr_syserror(int num)
                }
        }
 
-       if (!num) {
-               return "No error";
+       if (!num) return "No error";
+
+       p = buffer;
+       end = p + FR_STRERROR_BUFSIZE;
+
+#ifndef NDEBUG
+       /*
+        *      Prefix system errors with the macro name and number
+        *      if we're debugging.
+        */
+       if (num < (int)(sizeof(fr_errno_macro_names) / sizeof(*fr_errno_macro_names))) {
+               p += snprintf(p, end - p, "%s: ", fr_errno_macro_names[num]);
+       } else {
+               p += snprintf(p, end - p, "errno %i: ", num);
        }
+       if (p >= end) return p;
+#endif
 
        /*
         *      XSI-Compliant version
         */
 #if !defined(HAVE_FEATURES_H) || !defined(__GLIBC__) || ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 500) && ! _GNU_SOURCE)
-       if ((ret = strerror_r(num, buffer, (size_t)FR_STRERROR_BUFSIZE) != 0)) {
+       ret = strerror_r(num, p, end - p);
+       if (ret != 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));
@@ -186,8 +308,7 @@ char const *fr_syserror(int num)
         */
 #else
        {
-               char const *p;
-               p = strerror_r(num, buffer, (size_t)FR_STRERROR_BUFSIZE);
+               p = strerror_r(num, p, end - p);
                if (!p) {
 #  ifndef NDEBUG
                        fprintf(stderr, "strerror_r() failed to write error for errno %i to buffer %p "
@@ -196,6 +317,7 @@ char const *fr_syserror(int num)
                        buffer[0] = '\0';
                        return buffer;
                }
+
                return p;
        }
 #endif
index c093898..af6ee2c 100644 (file)
@@ -31,6 +31,28 @@ RCSID("$Id$")
 #include <pwd.h>
 #include <sys/uio.h>
 
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+
+/*
+ *     Some versions of Linux don't have closefrom(), but they will
+ *     have /proc.
+ *
+ *     BSD systems will generally have closefrom(), but not proc.
+ *
+ *     OSX doesn't have closefrom() or /proc/self/fd, but it does
+ *     have /dev/fd
+ */
+#ifdef __linux__
+#define CLOSEFROM_DIR "/proc/self/fd"
+#elif defined(__APPLE__)
+#define CLOSEFROM_DIR "/dev/fd"
+#else
+#undef HAVE_DIRENT_H
+#endif
+
+#endif
+
 #define FR_PUT_LE16(a, val)\
        do {\
                a[1] = ((uint16_t) (val)) >> 8;\
@@ -80,6 +102,28 @@ int fr_set_signal(int sig, sig_t func)
        return 0;
 }
 
+/** Uninstall a signal for a specific handler
+ *
+ * man sigaction says these are fine to call from a signal handler.
+ *
+ * @param sig SIGNAL
+ */
+int fr_unset_signal(int sig)
+{
+#ifdef HAVE_SIGACTION
+        struct sigaction act;
+
+        memset(&act, 0, sizeof(act));
+        act.sa_flags = 0;
+        sigemptyset(&act.sa_mask);
+        act.sa_handler = SIG_DFL;
+
+        return sigaction(sig, &act, NULL);
+#else
+        return signal(sig, SIG_DFL);
+#endif
+}
+
 static int _fr_trigger_talloc_ctx_free(fr_talloc_link_t *trigger)
 {
        if (trigger->armed) talloc_free(trigger->child);
@@ -198,6 +242,66 @@ char const *ip_ntoa(char *buffer, uint32_t ipaddr)
        return buffer;
 }
 
+/*
+ *     Parse decimal digits until we run out of decimal digits.
+ */
+static int ip_octet_from_str(char const *str, uint32_t *poctet)
+{
+       uint32_t octet;
+       char const *p = str;
+
+       if ((*p < '0') || (*p > '9')) {
+               return -1;
+       }
+
+       octet = 0;
+
+       while ((*p >= '0') && (*p <= '9')) {
+               octet *= 10;
+               octet += *p - '0';
+               p++;
+
+               if (octet > 255) return -1;
+       }
+
+
+       *poctet = octet;
+       return p - str;
+}
+
+static int ip_prefix_from_str(char const *str, uint32_t *paddr)
+{
+       int shift, length;
+       uint32_t octet;
+       uint32_t addr;
+       char const *p = str;
+
+       addr = 0;
+
+       for (shift = 24; shift >= 0; shift -= 8) {
+               length = ip_octet_from_str(p, &octet);
+               if (length <= 0) return -1;
+
+               addr |= octet << shift;
+               p += length;
+
+               /*
+                *      EOS or / means we're done.
+                */
+               if (!*p || (*p == '/')) break;
+
+               /*
+                *      We require dots between octets.
+                */
+               if (*p != '.') return -1;
+               p++;
+       }
+
+       *paddr = htonl(addr);
+       return p - str;
+}
+
+
 /** Parse an IPv4 address or IPv4 prefix in presentation format (and others)
  *
  * @param out Where to write the ip address value.
@@ -210,7 +314,7 @@ char const *ip_ntoa(char *buffer, uint32_t ipaddr)
 int fr_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback)
 {
        char *p;
-       unsigned int prefix;
+       unsigned int mask;
        char *eptr;
 
        /* Dotted quad + / + [0-9]{1,2} */
@@ -230,6 +334,7 @@ int fr_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, b
        }
 
        p = strchr(value, '/');
+
        /*
         *      192.0.2.2 is parsed as if it was /32
         */
@@ -242,6 +347,7 @@ int fr_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, b
                 */
                if ((value[0] == '*') && (value[1] == '\0')) {
                        out->ipaddr.ip4addr.s_addr = htonl(INADDR_ANY);
+
                /*
                 *      Convert things which are obviously integers to IP addresses
                 *
@@ -250,9 +356,10 @@ int fr_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, b
                 */
                } else if (is_integer(value) || ((value[0] == '0') && (value[1] == 'x'))) {
                        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);
+                               fr_strerror_printf("Failed to parse IPv4 addreess string \"%s\"", value);
                                return -1;
                        }
                } else if (ip_hton(out, AF_INET, value, fallback) < 0) return -1;
@@ -261,42 +368,33 @@ int fr_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, b
        }
 
        /*
-        *      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;
+       if (ip_prefix_from_str(buffer, &out->ipaddr.ip4addr.s_addr) <= 0) {
+               fr_strerror_printf("Failed to parse IPv4 address string \"%s\"", value);
+               return -1;
+       }
 
-       prefix = strtoul(p + 1, &eptr, 10);
-       if (prefix > 32) {
+       mask = strtoul(p + 1, &eptr, 10);
+       if (mask > 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);
+       if (mask < 32) {
+               out->ipaddr.ip4addr = fr_inaddr_mask(&out->ipaddr.ip4addr, mask);
        }
 
-       out->prefix = (uint8_t) prefix;
+       out->prefix = (uint8_t) mask;
        out->af = AF_INET;
 
        return 0;
@@ -511,12 +609,13 @@ int fr_pton_port(fr_ipaddr_t *out, uint16_t *port_out, char const *value, ssize_
         *      Host, IPv4 or IPv6 with no port
         */
        q = memchr(p, ':', len);
-       if (!q || !memchr(p, '.', len)) return fr_pton(out, p, len, af, resolve);
+       if (!q) return fr_pton(out, p, len, af, resolve);
 
        /*
         *      IPv4 or host, with port
         */
        if (fr_pton(out, p, (q - p), af, resolve) < 0) return -1;
+
 do_port:
        /*
         *      Valid ports are a maximum of 5 digits, so if the
@@ -1282,20 +1381,63 @@ int closefrom(int fd)
 {
        int i;
        int maxfd = 256;
+#ifdef HAVE_DIRENT_H
+       DIR *dir;
+#endif
+
+#ifdef F_CLOSEM
+       if (fcntl(fd, F_CLOSEM) == 0) {
+               return 0;
+       }
+#endif
+
+#ifdef F_MAXFD
+       maxfd = fcntl(fd, F_F_MAXFD);
+       if (maxfd >= 0) goto do_close;
+#endif
 
 #ifdef _SC_OPEN_MAX
        maxfd = sysconf(_SC_OPEN_MAX);
        if (maxfd < 0) {
-         maxfd = 256;
+               maxfd = 256;
        }
 #endif
 
+#ifdef HAVE_DIRENT_H
+       /*
+        *      Use /proc/self/fd directory if it exists.
+        */
+       dir = opendir(CLOSEFROM_DIR);
+       if (dir != NULL) {
+               long my_fd;
+               char *endp;
+               struct dirent *dp;
+
+               while ((dp = readdir(dir)) != NULL) {
+                       my_fd = strtol(dp->d_name, &endp, 10);
+                       if (my_fd <= 0) continue;
+
+                       if (*endp) continue;
+
+                       if (my_fd == dirfd(dir)) continue;
+
+                       if ((my_fd >= fd) && (my_fd <= maxfd)) {
+                               (void) close((int) my_fd);
+                       }
+               }
+               (void) closedir(dir);
+               return 0;
+       }
+#endif
+
+#ifdef F_MAXFD
+do_close:
+#endif
+
        if (fd > maxfd) return 0;
 
        /*
         *      FIXME: return EINTR?
-        *
-        *      Use F_CLOSEM?
         */
        for (i = fd; i < maxfd; i++) {
                close(i);
index 4c45fb4..1d73c76 100644 (file)
@@ -191,6 +191,29 @@ struct tm *gmtime_r(time_t const *l_clock, struct tm *result)
 }
 #endif
 
+#ifndef HAVE_VDPRINTF
+int vdprintf (int fd, char const *format, va_list args)
+{
+       int     ret;
+       FILE    *fp;
+       int     dup_fd;
+
+       dup_fd = dup(fd);
+       if (dup_fd < 0) return -1;
+
+       fp = fdopen(fd, "w");
+       if (!fp) {
+               close(dup_fd);
+               return -1;
+       }
+
+       ret = vfprintf(fp, format, args);
+       fclose(fp);     /* Also closes dup_fd */
+
+       return ret;
+}
+#endif
+
 #ifndef HAVE_GETTIMEOFDAY
 #ifdef WIN32
 /*
index e29deb1..c258c60 100644 (file)
@@ -536,8 +536,16 @@ RADIUS_PACKET **fr_packet_list_find_byreply(fr_packet_list_t *pl,
         *      TCP sockets are always bound to the correct src/dst IP/port
         */
        if (ps->proto == IPPROTO_TCP) {
-               my_request.src_ipaddr = reply->dst_ipaddr;
-               my_request.src_port = reply->dst_port;
+               reply->dst_ipaddr = ps->src_ipaddr;
+               reply->dst_port = ps->src_port;
+               reply->src_ipaddr = ps->dst_ipaddr;
+               reply->src_port = ps->dst_port;
+
+               my_request.src_ipaddr = ps->src_ipaddr;
+               my_request.src_port = ps->src_port;
+               my_request.dst_ipaddr = ps->dst_ipaddr;
+               my_request.dst_port = ps->dst_port;
+
        } else
 #endif
        {
@@ -547,10 +555,10 @@ RADIUS_PACKET **fr_packet_list_find_byreply(fr_packet_list_t *pl,
                        my_request.src_ipaddr = reply->dst_ipaddr;
                }
                my_request.src_port = ps->src_port;
-       }
 
-       my_request.dst_ipaddr = reply->src_ipaddr;
-       my_request.dst_port = reply->src_port;
+               my_request.dst_ipaddr = reply->src_ipaddr;
+               my_request.dst_port = reply->src_port;
+       }
 
 #ifdef WITH_TCP
        my_request.proto = reply->proto;
index ce5484f..c7701e2 100644 (file)
@@ -45,6 +45,26 @@ static int _fr_pair_free(VALUE_PAIR *vp) {
        return 0;
 }
 
+static VALUE_PAIR *fr_pair_alloc(TALLOC_CTX *ctx)
+{
+       VALUE_PAIR *vp;
+
+       vp = talloc_zero(ctx, VALUE_PAIR);
+       if (!vp) {
+               fr_strerror_printf("Out of memory");
+               return NULL;
+       }
+
+       vp->op = T_OP_EQ;
+       vp->tag = TAG_ANY;
+       vp->type = VT_NONE;
+
+       talloc_set_destructor(vp, _fr_pair_free);
+
+       return vp;
+}
+
+
 /** Dynamically allocate a new attribute
  *
  * Allocates a new attribute and a new dictionary attr if no DA is provided.
@@ -65,21 +85,18 @@ VALUE_PAIR *fr_pair_afrom_da(TALLOC_CTX *ctx, DICT_ATTR const *da)
                return NULL;
        }
 
-       vp = talloc_zero(ctx, VALUE_PAIR);
+       vp = fr_pair_alloc(ctx);
        if (!vp) {
                fr_strerror_printf("Out of memory");
                return NULL;
        }
 
+       /*
+        *      Use the 'da' to initialize more fields.
+        */
        vp->da = da;
-       vp->op = T_OP_EQ;
-       vp->tag = TAG_ANY;
-       vp->type = VT_NONE;
-
        vp->vp_length = da->flags.length;
 
-       talloc_set_destructor(vp, _fr_pair_free);
-
        return vp;
 }
 
@@ -105,10 +122,22 @@ VALUE_PAIR *fr_pair_afrom_num(TALLOC_CTX *ctx, unsigned int attr, unsigned int v
 
        da = dict_attrbyvalue(attr, vendor);
        if (!da) {
-               da = dict_unknown_afrom_fields(ctx, attr, vendor);
+               VALUE_PAIR *vp;
+
+               vp = fr_pair_alloc(ctx);
+               if (!vp) return NULL;
+
+               /*
+                *      Ensure that the DA is parented by the VP.
+                */
+               da = dict_unknown_afrom_fields(vp, attr, vendor);
                if (!da) {
+                       talloc_free(vp);
                        return NULL;
                }
+
+               vp->da = da;
+               return vp;
        }
 
        return fr_pair_afrom_da(ctx, da);
@@ -705,7 +734,10 @@ VALUE_PAIR *fr_pair_list_copy(TALLOC_CTX *ctx, VALUE_PAIR *from)
  *
  * @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] attr to match. If attribute PW_VENDOR_SPECIFIC and vendor 0,
+ *     will match (and therefore copy) only VSAs.
+ *     If attribute 0 and vendor 0  will match (and therefore copy) all
+ *     attributes.
  * @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.
@@ -723,14 +755,44 @@ VALUE_PAIR *fr_pair_list_copy_by_num(TALLOC_CTX *ctx, VALUE_PAIR *from,
             vp = fr_cursor_next(&src)) {
                VERIFY_VP(vp);
 
-               if ((vp->da->attr != attr) || (vp->da->vendor != vendor)) {
+               if (vp->da->flags.has_tag && !TAG_EQ(tag, vp->tag)) {
                        continue;
                }
 
-               if (vp->da->flags.has_tag && !TAG_EQ(tag, vp->tag)) {
+               /*
+                *      Attr/vendor of 0 means "move them all".
+                *      It's better than "fr_pair_copy(foo,bar);bar=NULL"
+                */
+               if ((attr == 0) && (vendor == 0)) {
+                       goto do_copy;
+               }
+
+               /*
+                *      vendor=0, attr = PW_VENDOR_SPECIFIC means
+                *      "match any vendor attribute".
+                */
+               if ((vendor == 0) && (attr == PW_VENDOR_SPECIFIC)) {
+                       /*
+                        *      It's a VSA: copy it over.
+                        */
+                       if (vp->da->vendor != 0) goto do_copy;
+
+                       /*
+                        *      It's Vendor-Specific: copy it over.
+                        */
+                       if (vp->da->attr == attr) goto do_copy;
+
+                       /*
+                        *      It's not a VSA: ignore it.
+                        */
+                       continue;
+               }
+
+               if ((vp->da->attr != attr) || (vp->da->vendor != vendor)) {
                        continue;
                }
 
+       do_copy:
                vp = fr_pair_copy(ctx, vp);
                if (!vp) {
                        fr_pair_list_free(&out);
@@ -1226,38 +1288,6 @@ finish:
 }
 
 
-static VALUE_PAIR *fr_pair_from_unkown(VALUE_PAIR *vp, DICT_ATTR const *da)
-{
-       ssize_t len;
-       VALUE_PAIR *vp2;
-
-       len = data2vp(NULL, NULL, NULL, NULL, da,
-                     vp->vp_octets, vp->vp_length, vp->vp_length,
-                     &vp2);
-       if (len < 0) return vp; /* it's really unknown */
-
-       if (vp2->da->flags.is_unknown) {
-               fr_pair_list_free(&vp2);
-               return vp;
-       }
-
-       /*
-        *      Didn't parse all of it.  Return the "unknown" one.
-        *
-        *      FIXME: it COULD have parsed 2 attributes and
-        *      then not the third, so returning 2 "knowns"
-        *      and 1 "unknown" is likely preferable.
-        */
-       if ((size_t) len < vp->vp_length) {
-               fr_pair_list_free(&vp2);
-               return vp;
-       }
-
-       fr_pair_steal(talloc_parent(vp), vp2);
-       fr_pair_list_free(&vp);
-       return vp2;
-}
-
 /** Create a valuepair from an ASCII attribute and value
  *
  * Where the attribute name is in the form:
@@ -1276,44 +1306,46 @@ static VALUE_PAIR *fr_pair_make_unknown(TALLOC_CTX *ctx,
                                        char const *attribute, char const *value,
                                        FR_TOKEN op)
 {
-       VALUE_PAIR      *vp;
+       VALUE_PAIR      *vp, *vp2;
        DICT_ATTR const *da;
 
        uint8_t         *data;
        size_t          size;
+       ssize_t         len;
+
+       vp = fr_pair_alloc(ctx);
+       if (!vp) return NULL;
 
-       da = dict_unknown_afrom_str(ctx, attribute);
-       if (!da) return NULL;
+       vp->da = dict_unknown_afrom_str(vp, attribute);
+       if (!vp->da) {
+               talloc_free(vp);
+               return NULL;
+       }
+
+       /*
+        *      No value.  Nothing more to do.
+        */
+       if (!value) return vp;
 
        /*
         *      Unknown attributes MUST be of type 'octets'
         */
-       if (value && (strncasecmp(value, "0x", 2) != 0)) {
+       if (strncasecmp(value, "0x", 2) != 0) {
                fr_strerror_printf("Unknown attribute \"%s\" requires a hex "
                                   "string, not \"%s\"", attribute, value);
-
-               dict_attr_free(&da);
+               talloc_free(vp);
                return NULL;
        }
 
        /*
-        *      We've now parsed the attribute properly, Let's create
-        *      it.  This next stop also looks the attribute up in the
-        *      dictionary, and creates the appropriate type for it.
+        *      Convert the hex data to binary.
         */
-       vp = fr_pair_afrom_da(ctx, da);
-       if (!vp) {
-               dict_attr_free(&da);
-               return NULL;
-       }
-
-       vp->op = (op == 0) ? T_OP_EQ : op;
-
-       if (!value) return vp;
-
        size = strlen(value + 2);
+
        vp->vp_length = size >> 1;
-       data = talloc_array(vp, uint8_t, vp->vp_length);
+       vp->vp_octets = data = talloc_array(vp, uint8_t, vp->vp_length);
+       vp->type = VT_DATA;
+       vp->op = (op == 0) ? T_OP_EQ : op;
 
        if (fr_hex2bin(data, vp->vp_length, value + 2, size) != vp->vp_length) {
                fr_strerror_printf("Invalid hex string");
@@ -1321,18 +1353,43 @@ static VALUE_PAIR *fr_pair_make_unknown(TALLOC_CTX *ctx,
                return NULL;
        }
 
-       vp->vp_octets = data;
-       vp->type = VT_DATA;
-
        /*
-        *      Convert unknowns to knowns
+        *      It's still unknown, return it as-is.
         */
        da = dict_attrbyvalue(vp->da->attr, vp->da->vendor);
-       if (da) {
-               return fr_pair_from_unkown(vp, da);
+       if (!da) return vp;
+
+       /*
+        *      It MIGHT be known.  See if we can decode the raw data
+        *      into a valid attribute.
+        */
+       len = data2vp(ctx, NULL, NULL, NULL, da,
+                     vp->vp_octets, vp->vp_length, vp->vp_length,
+                     &vp2);
+       if (len <= 0) return vp;
+
+       /*
+        *      It's still unknown.  Return the original VP.
+        */
+       if (vp2->da->flags.is_unknown) {
+               fr_pair_list_free(&vp2);
+               return vp;
        }
 
-       return vp;
+       /*
+        *      Didn't parse all of it.  Return the "unknown" one.
+        *
+        *      FIXME: it COULD have parsed 2 attributes and
+        *      then not the third, so returning 2 "knowns"
+        *      and 1 "unknown" is likely preferable.
+        */
+       if ((size_t) len < vp->vp_length) {
+               fr_pair_list_free(&vp2);
+               return vp;
+       }
+
+       fr_pair_list_free(&vp);
+       return vp2;
 }
 
 
@@ -1581,11 +1638,13 @@ int fr_pair_mark_xlat(VALUE_PAIR *vp, char const *value)
         *      valuepair should not already have a value.
         */
        if (vp->type != VT_NONE) {
+               fr_strerror_printf("Pair already has a value");
                return -1;
        }
 
        raw = talloc_typed_strdup(vp, value);
        if (!raw) {
+               fr_strerror_printf("Out of memory");
                return -1;
        }
 
@@ -1952,7 +2011,7 @@ int fr_pair_cmp(VALUE_PAIR *a, VALUE_PAIR *b)
 
                        if (!fr_assert(a->da->type == PW_TYPE_STRING)) return -1;
 
-                       slen = regex_compile(NULL, &preg, a->vp_strvalue, a->vp_length, false, false, false, true);
+                       slen = regex_compile(NULL, &preg, a->value.xlat, talloc_array_length(a->value.xlat) - 1, false, false, false, true);
                        if (slen <= 0) {
                                fr_strerror_printf("Error at offset %zu compiling regex for %s: %s",
                                                   -slen, a->da->name, fr_strerror());
index 0d11ef7..421732f 100644 (file)
@@ -436,6 +436,10 @@ char *vp_aprints_value(TALLOC_CTX *ctx, VALUE_PAIR const *vp, char quote)
 {
        VERIFY_VP(vp);
 
+       if (vp->type == VT_XLAT) {
+               return fr_aprints(ctx, vp->value.xlat, talloc_array_length(vp->value.xlat) - 1, quote);
+       }
+
        return value_data_aprints(ctx, vp->da->type, vp->da, &vp->data, vp->vp_length, quote);
 }
 
@@ -489,7 +493,7 @@ char *vp_aprints_type(TALLOC_CTX *ctx, PW_TYPE type)
  *  JSON value to.
  *
  * @param out Where to write the string.
- * @param outlen Lenth of output buffer.
+ * @param outlen Length of output buffer.
  * @param vp to print.
  * @return the length of data written to out, or a value >= outlen on truncation.
  */
@@ -648,7 +652,7 @@ static char const *vp_tokens[] = {
  * to a string.
  *
  * @param out Where to write the string.
- * @param outlen Lenth of output buffer.
+ * @param outlen Length of output buffer.
  * @param vp to print.
  * @return the length of data written to out, or a value >= outlen on truncation.
  */
index 7664cf9..53d45e2 100644 (file)
@@ -65,11 +65,6 @@ static void VP_HEXDUMP(char const *msg, uint8_t const *data, size_t len)
 
 
 /*
- *  The RFC says 4096 octets max, and most packets are less than 256.
- */
-#define MAX_PACKET_LEN 4096
-
-/*
  *     The maximum number of attributes which we allow in an incoming
  *     request.  If there are more attributes than this, the request
  *     is rejected.
@@ -184,7 +179,7 @@ static void print_hex_data(uint8_t const *ptr, int attrlen, int depth)
 }
 
 
-void rad_print_hex(RADIUS_PACKET *packet)
+void rad_print_hex(RADIUS_PACKET const *packet)
 {
        int i;
 
@@ -881,10 +876,7 @@ static ssize_t vp2data_any(RADIUS_PACKET const *packet,
        case PW_TYPE_STRING:
        case PW_TYPE_OCTETS:
                data = vp->data.ptr;
-               if (!data) {
-                       fr_strerror_printf("ERROR: Cannot encode NULL data");
-                       return -1;
-               }
+               if (!data) return 0;
                break;
 
        case PW_TYPE_IFID:
@@ -1363,9 +1355,9 @@ static ssize_t vp2attr_rfc(RADIUS_PACKET const *packet,
        ptr[0] = attribute & 0xff;
        ptr[1] = 2;
 
-       if (room > ((unsigned) 255 - ptr[1])) room = 255 - ptr[1];
+       if (room > 255) room = 255;
 
-       len = vp2data_any(packet, original, secret, 0, pvp, ptr + ptr[1], room);
+       len = vp2data_any(packet, original, secret, 0, pvp, ptr + ptr[1], room - ptr[1]);
        if (len <= 0) return len;
 
        ptr[1] += len;
@@ -1450,12 +1442,10 @@ static ssize_t vp2attr_vsa(RADIUS_PACKET const *packet,
 
        }
 
-       if (room > ((unsigned) 255 - (dv->type + dv->length))) {
-               room = 255 - (dv->type + dv->length);
-       }
+       if (room > 255) room = 255;
 
        len = vp2data_any(packet, original, secret, 0, pvp,
-                         ptr + dv->type + dv->length, room);
+                         ptr + dv->type + dv->length, room - (dv->type + dv->length));
        if (len <= 0) return len;
 
        if (dv->length) ptr[dv->type + dv->length - 1] += len;
@@ -1555,11 +1545,11 @@ int rad_vp2vsa(RADIUS_PACKET const *packet, RADIUS_PACKET const *original,
        lvalue = htonl(vp->da->vendor);
        memcpy(ptr + 2, &lvalue, 4);
 
-       if (room > ((unsigned) 255 - ptr[1])) room = 255 - ptr[1];
+       if (room > 255) room = 255;
 
        len = vp2attr_vsa(packet, original, secret, pvp,
                          vp->da->attr, vp->da->vendor,
-                         ptr + ptr[1], room);
+                         ptr + ptr[1], room - ptr[1]);
        if (len < 0) return len;
 
 #ifndef NDEBUG
@@ -1707,7 +1697,10 @@ int rad_vp2attr(RADIUS_PACKET const *packet, RADIUS_PACKET const *original,
         *      RFC format attributes take the fast path.
         */
        if (!vp->da->vendor) {
-               if (vp->da->attr > 255) return 0;
+               if (vp->da->attr > 255) {
+                       *pvp = vp->next;
+                       return 0;
+               }
 
                return rad_vp2rfc(packet, original, secret, pvp,
                                  start, room);
@@ -1815,7 +1808,7 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
         */
        reply = packet->vps;
        while (reply) {
-               size_t last_len;
+               size_t last_len, room;
                char const *last_name = NULL;
 
                VERIFY_VP(reply);
@@ -1844,6 +1837,20 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
                }
 
                /*
+                *      We allow zero-length strings in "unlang", but
+                *      skip them (except for CUI, thanks WiMAX!) on
+                *      all other attributes.
+                */
+               if (reply->vp_length == 0) {
+                       if ((reply->da->vendor != 0) ||
+                           ((reply->da->attr != PW_CHARGEABLE_USER_IDENTITY) &&
+                            (reply->da->attr != PW_MESSAGE_AUTHENTICATOR))) {
+                               reply = reply->next;
+                               continue;
+                       }
+               }
+
+               /*
                 *      Set the Message-Authenticator to the correct
                 *      length and initial value.
                 */
@@ -1859,8 +1866,11 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
                }
                last_name = reply->da->name;
 
-               len = rad_vp2attr(packet, original, secret, &reply, ptr,
-                                 ((uint8_t *) data) + sizeof(data) - ptr);
+               room = ((uint8_t *) data) + sizeof(data) - ptr;
+
+               if (room <= 2) break;
+
+               len = rad_vp2attr(packet, original, secret, &reply, ptr, room);
                if (len < 0) return -1;
 
                /*
@@ -1931,8 +1941,44 @@ int rad_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
        }
 
        /*
+        *      Set up the authentication vector with zero, or with
+        *      the original vector, prior to signing.
+        */
+       switch (packet->code) {
+       case PW_CODE_ACCOUNTING_REQUEST:
+       case PW_CODE_DISCONNECT_REQUEST:
+       case PW_CODE_COA_REQUEST:
+               memset(packet->vector, 0, AUTH_VECTOR_LEN);
+               break;
+
+       case PW_CODE_ACCESS_ACCEPT:
+       case PW_CODE_ACCESS_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:
+               if (!original) {
+                       fr_strerror_printf("ERROR: Cannot sign response packet without a request packet");
+                       return -1;
+               }
+               memcpy(packet->vector, original->vector, AUTH_VECTOR_LEN);
+               break;
+
+       case PW_CODE_ACCESS_REQUEST:
+       case PW_CODE_STATUS_SERVER:
+       default:
+               break;          /* packet->vector is already random bytes */
+       }
+
+#ifndef NDEBUG
+       if ((fr_debug_lvl > 3) && fr_log_fp) rad_print_hex(packet);
+#endif
+
+       /*
         *      If there's a Message-Authenticator, update it
-        *      now, BEFORE updating the authentication vector.
+        *      now.
         */
        if (packet->offset > 0) {
                uint8_t calc_auth_vector[AUTH_VECTOR_LEN];
@@ -1949,6 +1995,7 @@ int rad_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
                case PW_CODE_DISCONNECT_NAK:
                case PW_CODE_COA_REQUEST:
                case PW_CODE_COA_ACK:
+               case PW_CODE_COA_NAK:
                        memset(hdr->vector, 0, AUTH_VECTOR_LEN);
                        break;
 
@@ -1956,17 +2003,11 @@ int rad_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
                case PW_CODE_ACCESS_ACCEPT:
                case PW_CODE_ACCESS_REJECT:
                case PW_CODE_ACCESS_CHALLENGE:
-                       if (!original) {
-                               fr_strerror_printf("ERROR: Cannot sign response packet without a request packet");
-                               return -1;
-                       }
-                       memcpy(hdr->vector, original->vector,
-                              AUTH_VECTOR_LEN);
+                       memcpy(hdr->vector, original->vector, AUTH_VECTOR_LEN);
                        break;
 
-               default:        /* others have vector already set to zero */
+               default:
                        break;
-
                }
 
                /*
@@ -1979,21 +2020,20 @@ int rad_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
                            (uint8_t const *) secret, strlen(secret));
                memcpy(packet->data + packet->offset + 2,
                       calc_auth_vector, AUTH_VECTOR_LEN);
-
-               /*
-                *      Copy the original request vector back
-                *      to the raw packet.
-                */
-               memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN);
        }
 
        /*
+        *      Copy the request authenticator over to the packet.
+        */
+       memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN);
+
+       /*
         *      Switch over the packet code, deciding how to
         *      sign the packet.
         */
        switch (packet->code) {
                /*
-                *      Request packets are not signed, bur
+                *      Request packets are not signed, but
                 *      have a random authentication vector.
                 */
        case PW_CODE_ACCESS_REQUEST:
@@ -4295,8 +4335,7 @@ int rad_pwdecode(char *passwd, size_t pwlen, char const *secret,
  * This is per RFC-2868 which adds a two char SALT to the initial intermediate
  * value MD5 hash.
  */
-int rad_tunnel_pwencode(char *passwd, size_t *pwlen, char const *secret,
-                       uint8_t const *vector)
+ssize_t rad_tunnel_pwencode(char *passwd, size_t *pwlen, char const *secret, uint8_t const *vector)
 {
        uint8_t buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 3];
        unsigned char   digest[AUTH_VECTOR_LEN];
@@ -4378,8 +4417,7 @@ int rad_tunnel_pwencode(char *passwd, size_t *pwlen, char const *secret,
  * initial intermediate value, to differentiate it from the
  * above.
  */
-int rad_tunnel_pwdecode(uint8_t *passwd, size_t *pwlen, char const *secret,
-                       uint8_t const *vector)
+ssize_t rad_tunnel_pwdecode(uint8_t *passwd, size_t *pwlen, char const *secret, uint8_t const *vector)
 {
        FR_MD5_CTX  context, old;
        uint8_t         digest[AUTH_VECTOR_LEN];
index c4ebe21..355277c 100644 (file)
@@ -26,9 +26,6 @@ RCSID("$Id$")
 
 #ifdef WITH_TCP
 
-/* FIXME: into common RADIUS header? */
-#define MAX_PACKET_LEN 4096
-
 RADIUS_PACKET *fr_tcp_recv(int sockfd, int flags)
 {
        RADIUS_PACKET *packet = rad_alloc(NULL, false);
@@ -167,15 +164,6 @@ int fr_tcp_read_packet(RADIUS_PACKET *packet, int flags)
                                 packet->sockfd);
                }
 
-
-               if (is_radius_code(packet->code)) {
-                       DEBUG("Received %s packet from %s",
-                             fr_packet_codes[packet->code], buffer);
-               } else {
-                       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 */
index 3907908..8ae41b3 100644 (file)
@@ -182,10 +182,10 @@ static FR_TOKEN getthing(char const **ptr, char *buf, int buflen, bool tok,
 
        /* Skip whitespace */
        p = *ptr;
-       while (*p && isspace((int) *p))
-               p++;
 
-       if (*p == 0) {
+       while (*p && isspace((int) *p)) p++;
+
+       if (!*p) {
                *ptr = p;
                return T_EOL;
        }
@@ -197,18 +197,33 @@ static FR_TOKEN getthing(char const **ptr, char *buf, int buflen, bool tok,
                if (TOKEN_MATCH(p, t->name)) {
                        strcpy(buf, t->name);
                        p += strlen(t->name);
-                       while (isspace((int) *p))
-                               p++;
-                       *ptr = p;
-                       return (FR_TOKEN) t->number;
+
+                       rcode = t->number;
+                       goto done;
                }
        }
 
        /* Read word. */
        quote = '\0';
-       if ((*p == '"') ||
-           (*p == '\'') ||
-           (*p == '`')) {
+       switch (*p) {
+       default:
+               rcode = T_BARE_WORD;
+               break;
+
+       case '\'':
+               rcode = T_SINGLE_QUOTED_STRING;
+               break;
+
+       case '"':
+               rcode = T_DOUBLE_QUOTED_STRING;
+               break;
+
+       case '`':
+               rcode = T_BACK_QUOTED_STRING;
+               break;
+       }
+
+       if (rcode != T_BARE_WORD) {
                quote = *p;
                end = false;
                p++;
@@ -216,7 +231,59 @@ static FR_TOKEN getthing(char const **ptr, char *buf, int buflen, bool tok,
        s = buf;
 
        while (*p && buflen-- > 1) {
-               if (unescape && quote && (*p == '\\')) {
+               /*
+                *      We're looking for strings.  Stop on spaces, or
+                *      (if given a token list), on a token, or on a
+                *      comma.
+                */
+               if (!quote) {
+                       if (isspace((int) *p)) {
+                               break;
+                       }
+
+                       if (tok) {
+                               for (t = tokenlist; t->name; t++) {
+                                       if (TOKEN_MATCH(p, t->name)) {
+                                               *s++ = 0;
+                                               goto done;
+                                       }
+                               }
+                       }
+                       if (*p == ',') break;
+
+                       /*
+                        *      Copy the character over.
+                        */
+                       *s++ = *p++;
+                       continue;
+               } /* else there was a quotation character */
+
+               /*
+                *      Un-escaped quote character.  We're done.
+                */
+               if (*p == quote) {
+                       end = true;
+                       p++;
+                       break;
+               }
+
+               /*
+                *      Everything but backslash gets copied over.
+                */
+               if (*p != '\\') {
+                       *s++ = *p++;
+                       continue;
+               }
+
+               /*
+                *      There's nothing after the backslash, it's an error.
+                */
+               if (!p[1]) {
+                       fr_strerror_printf("Unterminated string");
+                       return T_INVALID;
+               }
+
+               if (unescape) {
                        p++;
 
                        switch (*p) {
@@ -229,10 +296,7 @@ static FR_TOKEN getthing(char const **ptr, char *buf, int buflen, bool tok,
                                case 't':
                                        *s++ = '\t';
                                        break;
-                               case '\0':
-                                       *s++ = '\\';
-                                       p--; /* force EOS */
-                                       break;
+
                                default:
                                        if (*p >= '0' && *p <= '9' &&
                                            sscanf(p, "%3o", &x) == 1) {
@@ -243,45 +307,26 @@ static FR_TOKEN getthing(char const **ptr, char *buf, int buflen, bool tok,
                                        break;
                        }
                        p++;
-                       continue;
-               }
-
-               /*
-                *      Deal with quotes and escapes, but don't mash
-                *      escaped characters into their non-escaped
-                *      equivalent.
-                */
-               if (!unescape && quote && (*p == '\\')) {
-                       if (!p[1]) continue; /* force end of string */
 
+               } else {
+                       /*
+                        *      Convert backslash-quote to quote, but
+                        *      leave everything else alone.
+                        */
                        if (p[1] == quote) { /* convert '\'' --> ' */
                                p++;
                        } else {
+                               if (buflen < 2) {
+                                       fr_strerror_printf("Truncated input");
+                                       return T_INVALID;
+                               }
+
                                *(s++) = *(p++);
                        }
                        *(s++) = *(p++);
-                       continue;
-               }
-
-               if (quote && (*p == quote)) {
-                       end = true;
-                       p++;
-                       break;
-               }
-               if (!quote) {
-                       if (isspace((int) *p))
-                               break;
-                       if (tok) {
-                               for (t = tokenlist; t->name; t++)
-                                       if (TOKEN_MATCH(p, t->name))
-                                               break;
-                               if (t->name != NULL)
-                                       break;
-                       }
-                       if (*p == ',') break; /* hack */
                }
-               *s++ = *p++;
        }
+
        *s++ = 0;
 
        if (quote && !end) {
@@ -289,29 +334,11 @@ static FR_TOKEN getthing(char const **ptr, char *buf, int buflen, bool tok,
                return T_INVALID;
        }
 
+done:
        /* Skip whitespace again. */
-       while (*p && isspace((int) *p))
-               p++;
-       *ptr = p;
-
-       /* we got SOME form of output string, even if it is empty */
-       switch (quote) {
-       default:
-               rcode = T_BARE_WORD;
-               break;
-
-       case '\'':
-               rcode = T_SINGLE_QUOTED_STRING;
-               break;
-
-       case '"':
-               rcode = T_DOUBLE_QUOTED_STRING;
-               break;
+       while (*p && isspace((int) *p)) p++;
 
-       case '`':
-               rcode = T_BACK_QUOTED_STRING;
-               break;
-       }
+       *ptr = p;
 
        return rcode;
 }
@@ -369,7 +396,7 @@ FR_TOKEN getstring(char const **ptr, char *buf, int buflen, bool unescape)
                return gettoken(ptr, buf, buflen, unescape);
        }
 
-       return getthing(ptr, buf, buflen, 0, fr_tokens, unescape);
+       return getthing(ptr, buf, buflen, false, fr_tokens, unescape);
 }
 
 /*
index 5f2ad75..ad026e3 100644 (file)
@@ -56,7 +56,7 @@ int value_data_cmp(PW_TYPE a_type, value_data_t const *a, size_t a_len,
        {
                size_t length;
 
-               if (a_len > b_len) {
+               if (a_len < b_len) {
                        length = a_len;
                } else {
                        length = b_len;
@@ -586,6 +586,9 @@ ssize_t value_data_from_str(TALLOC_CTX *ctx, value_data_t *dst,
                return -1;
 
        /* raw octets: 0x01020304... */
+#ifndef WITH_ASCEND_BINARY
+       do_octets:
+#endif
        case PW_TYPE_OCTETS:
        {
                uint8_t *p;
@@ -1514,7 +1517,7 @@ char *value_data_aprints(TALLOC_CTX *ctx,
 #ifdef WITH_ASCEND_BINARY
                p = talloc_array(ctx, char, 128);
                if (!p) return NULL;
-               print_abinary(p, 128, (uint8_t *) &data->filter, inlen, 0);
+               print_abinary(p, 128, (uint8_t const *) &data->filter, inlen, 0);
                break;
 #else
                  /* FALL THROUGH */
index 5527d60..cc538fe 100644 (file)
@@ -10,3 +10,4 @@ radwho
 radmin
 radconf2xml
 dhclient
+*_ext
index 10a0a3e..1bbd828 100644 (file)
@@ -327,13 +327,12 @@ int rad_postauth(REQUEST *request)
                /*
                 *      We WERE going to have a nice reply, but
                 *      something went wrong.  So we've got to run
-                *      Post-Auth-Type Reject, which is defined in the
-                *      dictionaries as having value "1".
+                *      Post-Auth-Type Reject.
                 */
                if (request->reply->code != PW_CODE_ACCESS_REJECT) {
                        RDEBUG("Using Post-Auth-Type Reject");
 
-                       process_post_auth(1, request);
+                       process_post_auth(PW_POST_AUTH_TYPE_REJECT, request);
                }
 
                fr_state_discard(request, request->packet);
@@ -709,6 +708,98 @@ int rad_virtual_server(REQUEST *request)
        RDEBUG("Virtual server %s received request", request->server);
        rdebug_pair_list(L_DBG_LVL_1, request, request->packet->vps, NULL);
 
+       if (!request->username) {
+               request->username = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+       }
+
+       /*
+        *      Complain about possible issues related to tunnels.
+        */
+       if (request->parent && request->parent->username && request->username) {
+               /*
+                *      Look at the full User-Name with realm.
+                */
+               if (request->parent->username->da->attr == PW_STRIPPED_USER_NAME) {
+                       vp = fr_pair_find_by_num(request->parent->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+                       rad_assert(vp != NULL);
+               } else {
+                       vp = request->parent->username;
+               }
+
+               /*
+                *      If the names aren't identical, we do some detailed checks.
+                */
+               if (strcmp(vp->vp_strvalue, request->username->vp_strvalue) != 0) {
+                       char const *outer, *inner;
+
+                       outer = strchr(vp->vp_strvalue, '@');
+
+                       /*
+                        *      If there's no realm, or there's a user identifier before
+                        *      the realm name, check the user identifier.
+                        *
+                        *      It SHOULD be "anonymous", or "anonymous@realm"
+                        */
+                       if (outer) {
+                               if ((outer != vp->vp_strvalue) &&
+                                   ((vp->vp_length < 10) || (memcmp(vp->vp_strvalue, "anonymous@", 10) != 0))) {
+                                       RWDEBUG("Outer User-Name is not anonymized.  User privacy is compromised.");
+                               } /* else it is anonymized */
+
+                               /*
+                                *      Check when there's no realm, and without the trailing '@'
+                                */
+                       } else if ((vp->vp_length < 9) || (memcmp(vp->vp_strvalue, "anonymous", 9) != 0)) {
+                                       RWDEBUG("Outer User-Name is not anonymized.  User privacy is compromised.");
+
+                       } /* else the user identifier is anonymized */
+
+                       /*
+                        *      Look for an inner realm, which may or may not exist.
+                        */
+                       inner = strchr(request->username->vp_strvalue, '@');
+                       if (outer && inner) {
+                               outer++;
+                               inner++;
+
+                               /*
+                                *      The realms are different, do
+                                *      more detailed checks.
+                                */
+                               if (strcmp(outer, inner) != 0) {
+                                       size_t outer_len, inner_len;
+
+                                       outer_len = vp->vp_length;
+                                       outer_len -= (outer - vp->vp_strvalue);
+
+                                       inner_len = request->username->vp_length;
+                                       inner_len -= (inner - request->username->vp_strvalue);
+
+                                       /*
+                                        *      Inner: secure.example.org
+                                        *      Outer: example.org
+                                        */
+                                       if (inner_len > outer_len) {
+                                               char const *suffix;
+
+                                               suffix = inner + (inner_len - outer_len) - 1;
+
+                                               if ((*suffix != '.') ||
+                                                   (strcmp(suffix + 1, outer) != 0)) {
+                                                       RWDEBUG("Possible spoofing: Inner realm '%s' is not a subdomain of the outer realm '%s'", inner, outer);
+                                               }
+
+                                       } else {
+                                               RWDEBUG("Possible spoofing: Inner realm and outer realms are different");
+                                       }
+                               }
+                       }
+
+               } else {
+                       RWDEBUG("Outer and inner identities are the same.  User privacy is compromised.");
+               }
+       }
+
        RDEBUG("server %s {", request->server);
        RINDENT();
 
index 2f38f77..4ae14e5 100644 (file)
@@ -83,11 +83,31 @@ void cbtls_msg(int write_p, int msg_version, int content_type,
        tls_session_t *state = (tls_session_t *)arg;
 
        /*
+        *      OpenSSL 1.0.2 calls this function with 'pseudo'
+        *      content types.  Which breaks our tracking of
+        *      the SSL Session state.
+        */
+       if ((msg_version == 0) && (content_type > UINT8_MAX)) {
+               DEBUG4("Ignoring cbtls_msg call with pseudo content type %i, version %i",
+                      content_type, msg_version);
+               return;
+       }
+
+       if ((write_p != 0) && (write_p != 1)) {
+               DEBUG4("Ignoring cbtls_msg call with invalid write_p %d", write_p);
+               return;
+       }
+
+       /*
         *      Work around bug #298, where we may be called with a NULL
         *      argument.  We should really log a serious error
         */
        if (!state) return;
 
+       /*
+        *      0 - received (from peer)
+        *      1 - sending (to peer)
+        */
        state->info.origin = write_p;
        state->info.content_type = content_type;
        state->info.record_len = len;
index 40f9cd8..e991bf7 100644 (file)
@@ -1,5 +1,5 @@
-install: install.sbindir $(R)$(sbindir)/checkrad
+install: $(R)$(sbindir)/checkrad
 
-$(R)$(sbindir)/checkrad: src/main/checkrad
+$(R)$(sbindir)/checkrad: src/main/checkrad | $(R)$(sbindir)
        @echo INSTALL $(notdir $<)
        @$(INSTALL) -m 755 $< $(R)$(sbindir)
index 00229d0..763d7bc 100644 (file)
@@ -478,9 +478,7 @@ RADCLIENT *client_find_old(fr_ipaddr_t const *ipaddr)
 static fr_ipaddr_t cl_ipaddr;
 static uint32_t cl_netmask;
 static char const *cl_srcipaddr = NULL;
-#ifdef WITH_TCP
 static char const *hs_proto = NULL;
-#endif
 
 #ifdef WITH_TCP
 static CONF_PARSER limit_config[] = {
index 099bb78..d3b729f 100644 (file)
@@ -24,6 +24,7 @@
 #ifdef WITH_COMMAND_SOCKET
 
 #include <freeradius-devel/parser.h>
+#include <freeradius-devel/modcall.h>
 #include <freeradius-devel/md5.h>
 #include <freeradius-devel/channel.h>
 
@@ -117,12 +118,9 @@ static FR_NAME_NUMBER mode_names[] = {
        { NULL, 0 }
 };
 
-#ifndef HAVE_GETPEEREID
+#if !defined(HAVE_GETPEEREID) && defined(SO_PEERCRED)
 static int getpeereid(int s, uid_t *euid, gid_t *egid)
 {
-#ifndef SO_PEERCRED
-       return -1;
-#else
        struct ucred cr;
        socklen_t cl = sizeof(cr);
 
@@ -133,8 +131,11 @@ static int getpeereid(int s, uid_t *euid, gid_t *egid)
        *euid = cr.uid;
        *egid = cr.gid;
        return 0;
-#endif /* SO_PEERCRED */
 }
+
+/* we now have getpeereid() in this file */
+#define HAVE_GETPEEREID (1)
+
 #endif /* HAVE_GETPEEREID */
 
 /** Initialise a socket for use with peercred authentication
@@ -1350,6 +1351,8 @@ static int command_debug_condition(rad_listen_t *listener, int argc, char *argv[
                return CMD_FAIL;
        }
 
+       (void) modcall_pass2_condition(new_condition);
+
        /*
         *      Delete old condition.
         *
@@ -2252,7 +2255,7 @@ static FR_NAME_NUMBER state_names[] = {
 static int command_stats_detail(rad_listen_t *listener, int argc, char *argv[])
 {
        rad_listen_t *this;
-       listen_detail_t *data;
+       listen_detail_t *data, *needle;
        struct stat buf;
 
        if (argc == 0) {
@@ -2264,10 +2267,11 @@ static int command_stats_detail(rad_listen_t *listener, int argc, char *argv[])
        for (this = main_config.listen; this != NULL; this = this->next) {
                if (this->type != RAD_LISTEN_DETAIL) continue;
 
-               data = this->data;
-               if (strcmp(argv[1], data->filename) != 0) continue;
-
-               break;
+               needle = this->data;
+               if (!strcmp(argv[0], needle->filename)) {
+                       data = needle;
+                       break;
+               }
        }
 
        if (!data) {
@@ -2309,23 +2313,38 @@ static int command_stats_home_server(rad_listen_t *listener, int argc, char *arg
        home_server_t *home;
 
        if (argc == 0) {
-               cprintf_error(listener, "Must specify [auth/acct] OR <ipaddr> <port>\n");
+               cprintf_error(listener, "Must specify [auth|acct|coa|disconnect] OR <ipaddr> <port>\n");
                return 0;
        }
 
        if (argc == 1) {
+               if (strcmp(argv[0], "auth") == 0) {
+                       return command_print_stats(listener,
+                                                  &proxy_auth_stats, 1, 1);
+               }
+
 #ifdef WITH_ACCOUNTING
                if (strcmp(argv[0], "acct") == 0) {
                        return command_print_stats(listener,
                                                   &proxy_acct_stats, 0, 1);
                }
 #endif
-               if (strcmp(argv[0], "auth") == 0) {
+
+#ifdef WITH_ACCOUNTING
+               if (strcmp(argv[0], "coa") == 0) {
                        return command_print_stats(listener,
-                                                  &proxy_auth_stats, 1, 1);
+                                                  &proxy_coa_stats, 0, 1);
                }
+#endif
+
+#ifdef WITH_ACCOUNTING
+               if (strcmp(argv[0], "disconnect") == 0) {
+                       return command_print_stats(listener,
+                                                  &proxy_dsc_stats, 0, 1);
+               }
+#endif
 
-               cprintf_error(listener, "Should specify [auth/acct]\n");
+               cprintf_error(listener, "Should specify [auth|acct|coa|disconnect]\n");
                return 0;
        }
 
@@ -2356,7 +2375,7 @@ static int command_stats_client(rad_listen_t *listener, int argc, char *argv[])
                 */
                fake.auth = radius_auth_stats;
 #ifdef WITH_ACCOUNTING
-               fake.auth = radius_acct_stats;
+               fake.acct = radius_acct_stats;
 #endif
 #ifdef WITH_COA
                fake.coa = radius_coa_stats;
@@ -2583,7 +2602,7 @@ static fr_command_table_t command_table_stats[] = {
 
 #ifdef WITH_PROXY
        { "home_server", FR_READ,
-         "stats home_server [<ipaddr>/auth/acct] <port> [udp|tcp] - show statistics for given home server (ipaddr and port), or for all home servers (auth or acct)",
+         "stats home_server [<ipaddr>|auth|acct|coa|disconnect] <port> [udp|tcp] - show statistics for given home server (ipaddr and port), or for all home servers (auth or acct)",
          command_stats_home_server, NULL },
 #endif
 
@@ -2675,7 +2694,7 @@ static int command_socket_parse_unix(CONF_SECTION *cs, rad_listen_t *this)
         *      Can't get uid or gid of connecting user, so can't do
         *      peercred authentication.
         */
-#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED)
+#ifndef HAVE_GETPEEREID
        if (sock->peercred && (sock->uid_name || sock->gid_name)) {
                ERROR("System does not support uid or gid authentication for sockets");
                return -1;
@@ -3025,7 +3044,12 @@ static int command_domain_recv_co(rad_listen_t *listener, fr_cs_buffer_t *co)
 /*
  *     Write 32-bit magic number && version information.
  */
-static int command_write_magic(int newfd, listen_socket_t *sock)
+static int command_write_magic(int newfd,
+#ifndef WITH_TCP
+                              UNUSED
+#endif
+                              listen_socket_t *sock
+       )
 {
        ssize_t r;
        uint32_t magic;
@@ -3050,6 +3074,7 @@ static int command_write_magic(int newfd, listen_socket_t *sock)
        r = fr_channel_write(newfd, FR_CHANNEL_INIT_ACK, buffer, 8);
        if (r <= 0) goto do_close;
 
+#ifdef WITH_TCP
        /*
         *      Write an initial challenge
         */
@@ -3067,11 +3092,12 @@ static int command_write_magic(int newfd, listen_socket_t *sock)
                r = fr_channel_write(newfd, FR_CHANNEL_AUTH_CHALLENGE, co->buffer, 16);
                if (r <= 0) goto do_close;
        }
+#endif
 
        return 0;
 }
 
-
+#ifdef WITH_TCP
 static int command_tcp_recv(rad_listen_t *this)
 {
        ssize_t r;
@@ -3079,16 +3105,18 @@ static int command_tcp_recv(rad_listen_t *this)
        fr_cs_buffer_t *co = (void *) sock->packet;
        fr_channel_type_t channel;
 
-       rad_assert(co != NULL);
+       if (!co) {
+       do_close:
+               command_close_socket(this);
+               return 0;
+       }
 
        if (!co->auth) {
                uint8_t expected[16];
 
                r = fr_channel_read(this->fd, &channel, co->buffer, 16);
                if ((r != 16) || (channel != FR_CHANNEL_AUTH_RESPONSE)) {
-               do_close:
-                       command_close_socket(this);
-                       return 0;
+                       goto do_close;
                }
 
                fr_hmac_md5(expected, (void const *) sock->client->secret,
@@ -3108,6 +3136,7 @@ static int command_tcp_recv(rad_listen_t *this)
        return command_domain_recv_co(this, co);
 }
 
+
 /*
  *     Should never be called.  The functions should just call write().
  */
@@ -3115,6 +3144,7 @@ static int command_tcp_send(UNUSED rad_listen_t *listener, UNUSED REQUEST *reque
 {
        return 0;
 }
+#endif
 
 static int command_domain_recv(rad_listen_t *listener)
 {
@@ -3148,7 +3178,7 @@ static int command_domain_accept(rad_listen_t *listener)
                return 0;
        }
 
-#if defined(HAVE_GETPEEREID) || defined (SO_PEERCRED)
+#ifdef HAVE_GETPEEREID
        /*
         *      Perform user authentication.
         */
index 855c0bb..611c386 100644 (file)
@@ -122,7 +122,6 @@ struct conf_part {
 typedef struct cf_file_t {
        char const      *filename;
        CONF_SECTION    *cs;
-       bool            input;
        struct stat     buf;
 } cf_file_t;
 
@@ -333,7 +332,6 @@ static FILE *cf_file_open(CONF_SECTION *cs, char const *filename)
 
        file->filename = filename;
        file->cs = cs;
-       file->input = true;
 
        if (fstat(fd, &file->buf) == 0) {
 #ifdef S_IWOTH
@@ -362,10 +360,9 @@ static FILE *cf_file_open(CONF_SECTION *cs, char const *filename)
 }
 
 /*
- *     Do some checks on the file as an "input" file.  i.e. one read
- *     by a module.
+ *     Do some checks on the file
  */
-static bool cf_file_input(CONF_SECTION *cs, char const *filename)
+static bool cf_file_check(CONF_SECTION *cs, char const *filename, bool check_perms)
 {
        cf_file_t *file;
        CONF_DATA *cd;
@@ -383,14 +380,18 @@ static bool cf_file_input(CONF_SECTION *cs, char const *filename)
 
        file->filename = filename;
        file->cs = cs;
-       file->input = true;
 
        if (stat(filename, &file->buf) < 0) {
-               ERROR("Unable to open file \"%s\": %s", filename, fr_syserror(errno));
+               ERROR("Unable to check file \"%s\": %s", filename, fr_syserror(errno));
                talloc_free(file);
                return false;
        }
 
+       if (!check_perms) {
+               talloc_free(file);
+               return true;
+       }
+
 #ifdef S_IWOTH
        if ((file->buf.st_mode & S_IWOTH) != 0) {
                ERROR("Configuration file %s is globally writable.  "
@@ -440,11 +441,13 @@ static int file_callback(void *ctx, void *data)
         *      The file changed, we'll need to re-read it.
         */
        if (buf.st_mtime != file->buf.st_mtime) {
-               if (!file->input) {
-                       cb->rcode |= CF_FILE_CONFIG;
-               } else {
-                       (void) cb->callback(cb->modules, file->cs);
+
+               if (cb->callback(cb->modules, file->cs)) {
                        cb->rcode |= CF_FILE_MODULE;
+                       DEBUG3("HUP: Changed module file %s", file->filename);
+               } else {
+                       DEBUG3("HUP: Changed config file %s", file->filename);
+                       cb->rcode |= CF_FILE_CONFIG;
                }
        }
 
@@ -568,7 +571,7 @@ CONF_PAIR *cf_pair_dup(CONF_SECTION *parent, CONF_PAIR *cp)
        /*
         *      Avoid mallocs if possible.
         */
-       if (!cp->item.filename || (strcmp(parent->item.filename, cp->item.filename) == 0)) {
+       if (!cp->item.filename || (parent->item.filename && !strcmp(parent->item.filename, cp->item.filename))) {
                new->item.filename = parent->item.filename;
        } else {
                new->item.filename = talloc_strdup(new, cp->item.filename);
@@ -1384,7 +1387,7 @@ static inline int fr_item_validate_ipaddr(CONF_SECTION *cs, char const *name, PW
 int cf_item_parse(CONF_SECTION *cs, char const *name, unsigned int type, void *data, char const *dflt)
 {
        int rcode;
-       bool deprecated, required, attribute, secret, file_input, cant_be_empty, tmpl, multi;
+       bool deprecated, required, attribute, secret, file_input, cant_be_empty, tmpl, multi, file_exists;
        char **q;
        char const *value;
        CONF_PAIR *cp = NULL;
@@ -1399,6 +1402,7 @@ int cf_item_parse(CONF_SECTION *cs, char const *name, unsigned int type, void *d
        attribute = (type & PW_TYPE_ATTRIBUTE);
        secret = (type & PW_TYPE_SECRET);
        file_input = (type == PW_TYPE_FILE_INPUT);      /* check, not and */
+       file_exists = (type == PW_TYPE_FILE_EXISTS);    /* check, not and */
        cant_be_empty = (type & PW_TYPE_NOT_EMPTY);
        tmpl = (type & PW_TYPE_TMPL);
        multi = (type & PW_TYPE_MULTI);
@@ -1434,23 +1438,38 @@ int cf_item_parse(CONF_SECTION *cs, char const *name, unsigned int type, void *d
         */
        } else {
                CONF_PAIR *next = cp;
+
                value = cp->value;
                cp->parsed = true;
                c_item = &cp->item;
 
-               /*
-                *      @fixme We should actually validate
-                *      the value of the pairs too
-                */
-               if (multi) while ((next = cf_pair_find_next(cs, next, name))) {
-                       next->parsed = true;
-               }
-
                if (deprecated) {
                        cf_log_err(c_item, "Configuration item \"%s\" is deprecated", name);
-
                        return -2;
                }
+
+               /*
+                *      A quick check to see if the next item is the same.
+                */
+               if (!multi && cp->item.next && (cp->item.next->type == CONF_ITEM_PAIR)) {
+                       next = cf_item_to_pair(cp->item.next);
+
+                       if (strcmp(next->attr, name) == 0) {
+                               WARN("%s[%d]: Ignoring duplicate configuration item '%s'",
+                                    next->item.filename ? next->item.filename : "unknown",
+                                    next->item.lineno, name);
+                       }
+               }
+                                                                                  
+               if (multi) {
+                       while ((next = cf_pair_find_next(cs, next, name)) != NULL) {
+                               /*
+                                *      @fixme We should actually validate
+                                *      the value of the pairs too
+                                */
+                               next->parsed = true;
+                       };
+               }
        }
 
        if (!value) {
@@ -1634,7 +1653,11 @@ int cf_item_parse(CONF_SECTION *cs, char const *name, unsigned int type, void *d
                 *      to be caught as early as possible, during
                 *      server startup.
                 */
-               if (*q && file_input && !cf_file_input(cs, *q)) {
+               if (*q && file_input && !cf_file_check(cs, *q, true)) {
+                       return -1;
+               }
+
+               if (*q && file_exists && !cf_file_check(cs, *q, false)) {
                        return -1;
                }
                break;
index 2df1619..81c8963 100644 (file)
@@ -784,6 +784,11 @@ static void *fr_connection_get_internal(fr_connection_pool_t *pool, bool spawn)
 
        if (!pool) return NULL;
 
+       /*
+        *      Allow CTRL-C to kill the server in debugging mode.
+        */
+       if (main_config.exiting) return NULL;
+
 #ifdef HAVE_PTHREAD_H
        if (spawn) pthread_mutex_lock(&pool->mutex);
 #endif
@@ -1405,6 +1410,15 @@ void *fr_connection_reconnect(fr_connection_pool_t *pool, void *conn)
        if (!pool || !conn) return NULL;
 
        /*
+        *      Don't allow opening of new connections if we're trying
+        *      to exit.
+        */
+       if (main_config.exiting) {
+               fr_connection_release(pool, conn);
+               return NULL;
+       }
+
+       /*
         *      If fr_connection_find is successful the pool is now locked
         */
        this = fr_connection_find(pool, conn);
index da52235..0d31e38 100644 (file)
@@ -203,6 +203,20 @@ static int detail_open(rad_listen_t *this)
         */
        data->fp = NULL;
        data->work_fd = open(data->filename_work, O_RDWR);
+
+       /*
+        *      Couldn't open it for a reason OTHER than "it doesn't
+        *      exist".  Complain and tell the admin.
+        */
+       if ((data->work_fd < 0) && (errno != ENOENT)) {
+               ERROR("Failed opening detail file %s: %s",
+                     data->filename_work, fr_syserror(errno));
+               return 0;
+       }
+
+       /*
+        *      The file doesn't exist.  Poll for it again.
+        */
        if (data->work_fd < 0) {
 #ifndef HAVE_GLOB_H
                return 0;
@@ -257,7 +271,11 @@ static int detail_open(rad_listen_t *this)
                 *      And try to open the filename.
                 */
                data->work_fd = open(data->filename_work, O_RDWR);
-               if (data->work_fd < 0) return 0;
+               if (data->work_fd < 0) {
+                       ERROR("Failed opening detail file %s: %s",
+                                       data->filename_work, fr_syserror(errno));
+                       return 0;
+               }
 #endif
        } /* else detail.work existed, and we opened it */
 
index bd49e8b..64be496 100644 (file)
@@ -346,6 +346,41 @@ finish:
 }
 
 
+static size_t regex_escape(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
+{
+       char *p = out;
+
+       while (*in && (outlen > 2)) {
+               switch (*in) {
+               case '\\':
+               case '.':
+               case '*':
+               case '+':
+               case '?':
+               case '|':
+               case '^':
+               case '$':
+               case '[':       /* we don't list close braces */
+               case '{':
+               case '(':
+                       if (outlen < 3) goto done;
+
+                       *(p++) = '\\';
+                       outlen--;
+                       /* FALL-THROUGH */
+
+               default:
+                       *(p++) = *(in++);
+                       outlen--;
+                       break;
+               }
+       }
+
+done:
+       *(p++) = '\0';
+       return p - out;
+}
+
 
 /** Convert both operands to the same type
  *
@@ -372,6 +407,8 @@ static int cond_normalise_and_cmp(REQUEST *request, fr_cond_t const *c,
        value_data_t lhs_cast, rhs_cast;
        void *lhs_cast_buff = NULL, *rhs_cast_buff = NULL;
 
+       xlat_escape_t escape = NULL;
+
        /*
         *      Cast operand to correct type.
         *
@@ -415,7 +452,11 @@ do {\
         *      Regular expressions need both operands to be strings
         */
 #ifdef HAVE_REGEX
-       if (map->op == T_OP_REG_EQ) cast_type = PW_TYPE_STRING;
+       if (map->op == T_OP_REG_EQ) {
+               cast_type = PW_TYPE_STRING;
+
+               if (map->rhs->type == TMPL_TYPE_XLAT_STRUCT) escape = regex_escape;
+       }
        else
 #endif
        /*
@@ -519,7 +560,7 @@ do {\
                if (map->rhs->type != TMPL_TYPE_LITERAL) {
                        char *p;
 
-                       ret = tmpl_aexpand(request, &p, request, map->rhs, NULL, NULL);
+                       ret = tmpl_aexpand(request, &p, request, map->rhs, escape, NULL);
                        if (ret < 0) {
                                EVAL_DEBUG("FAIL [%i]", __LINE__);
                                rcode = -1;
@@ -574,6 +615,7 @@ finish:
        return rcode;
 }
 
+
 /** Evaluate a map
  *
  * @param[in] request the REQUEST
index d8a73c3..77fdd2e 100644 (file)
@@ -436,7 +436,7 @@ int radius_readfrom_program(int fd, pid_t pid, int timeout,
                rcode = select(fd + 1, &fds, NULL, NULL, &wake);
                if (rcode == 0) {
                too_long:
-                       DEBUG("Child PID %u is taking too much time: forcing failure and killing child.", pid);
+                       DEBUG("Child PID %u is taking too much time: forcing failure and killing child.", (unsigned int) pid);
                        kill(pid, SIGTERM);
                        close(fd); /* should give SIGPIPE to child, too */
 
index 5388ca0..edafe5f 100644 (file)
@@ -41,6 +41,7 @@ typedef struct exfile_entry_t {
 struct exfile_t {
        uint32_t        max_entries;    //!< How many file descriptors we keep track of.
        uint32_t        max_idle;       //!< Maximum idle time for a descriptor.
+       time_t          last_cleaned;
 
 #ifdef HAVE_PTHREAD_H
        pthread_mutex_t mutex;
@@ -124,6 +125,17 @@ exfile_t *exfile_init(TALLOC_CTX *ctx, uint32_t max_entries, uint32_t max_idle,
        return ef;
 }
 
+
+static void exfile_cleanup_entry(exfile_entry_t *entry)
+{
+       TALLOC_FREE(entry->filename);
+
+       close(entry->fd);
+       entry->hash = 0;
+       entry->fd = -1;
+       entry->dup = -1;
+}
+
 /** Open a new log file, or maybe an existing one.
  *
  * When multithreaded, the FD is locked via a mutex.  This way we're
@@ -137,7 +149,7 @@ exfile_t *exfile_init(TALLOC_CTX *ctx, uint32_t max_entries, uint32_t max_idle,
  */
 int exfile_open(exfile_t *ef, char const *filename, mode_t permissions, bool append)
 {
-       uint32_t i, tries;
+       int i, tries, unused, oldest;
        uint32_t hash;
        time_t now = time(NULL);
        struct stat st;
@@ -145,69 +157,81 @@ int exfile_open(exfile_t *ef, char const *filename, mode_t permissions, bool app
        if (!ef || !filename) return -1;
 
        hash = fr_hash_string(filename);
+       unused = -1;
 
        PTHREAD_MUTEX_LOCK(&ef->mutex);
 
        /*
-        *      Clean up old entries.
+        *      Clean up idle entries.
         */
-       for (i = 0; i < ef->max_entries; i++) {
-               if (!ef->entries[i].filename) continue;
-               if ((ef->entries[i].last_used + ef->max_idle) < now) {
+       if (now > (ef->last_cleaned + 1)) {
+               ef->last_cleaned = now;
+
+               for (i = 0; i < (int) ef->max_entries; i++) {
+                       if (!ef->entries[i].filename) continue;
+
+                       if ((ef->entries[i].last_used + ef->max_idle) >= now) continue;
+
                        /*
                         *      This will block forever if a thread is
                         *      doing something stupid.
                         */
-                       TALLOC_FREE(ef->entries[i].filename);
-                       close(ef->entries[i].fd);
+                       exfile_cleanup_entry(&ef->entries[i]);
                }
        }
 
        /*
-        *      Find the matching entry.
+        *      Find the matching entry, or an unused one.
+        *
+        *      Also track which entry is the oldest, in case there
+        *      are no unused entries.
         */
-       for (i = 0; i < ef->max_entries; i++) {
-               if (!ef->entries[i].filename) continue;
+       oldest = -1;
+       for (i = 0; i < (int) ef->max_entries; i++) {
+               if (!ef->entries[i].filename) {
+                       if (unused < 0) unused = i;
+                       continue;
+               }
 
-               if (ef->entries[i].hash == hash) {
-                       /*
-                        *      Same hash but different filename.  Give up.
-                        */
-                       if (strcmp(ef->entries[i].filename, filename) != 0) {
-                               PTHREAD_MUTEX_UNLOCK(&ef->mutex);
-                               return -1;
-                       }
-                       /*
-                        *      Someone else failed to create the entry.
-                        */
-                       if (!ef->entries[i].filename) {
-                               PTHREAD_MUTEX_UNLOCK(&ef->mutex);
-                               return -1;
-                       }
-                       goto do_return;
+               if ((oldest < 0) ||
+                   (ef->entries[i].last_used < ef->entries[oldest].last_used)) {
+                       oldest = i;
                }
+
+               /*
+                *      Hash comparisons are fast.  String comparisons are slow.
+                */
+               if (ef->entries[i].hash != hash) continue;
+
+               /*
+                *      But we still need to do string comparisons if
+                *      the hash matches, because 1/2^16 filenames
+                *      will result in a hash collision.  And that's
+                *      enough filenames in a long-running server to
+                *      ensure that it happens.
+                */
+               if (strcmp(ef->entries[i].filename, filename) != 0) continue;
+
+               goto do_return;
        }
 
        /*
-        *      Find an unused entry
+        *      There are no unused entries, free the oldest one.
         */
-       for (i = 0; i < ef->max_entries; i++) {
-               if (!ef->entries[i].filename) break;
-       }
-
-       if (i >= ef->max_entries) {
-               fr_strerror_printf("Too many different filenames");
-               PTHREAD_MUTEX_UNLOCK(&(ef->mutex));
-               return -1;
+       if (unused < 0) {
+               exfile_cleanup_entry(&ef->entries[oldest]);
+               unused = oldest;
        }
 
        /*
         *      Create a new entry.
         */
+       i = unused;
 
        ef->entries[i].hash = hash;
        ef->entries[i].filename = talloc_strdup(ef->entries, filename);
        ef->entries[i].fd = -1;
+       ef->entries[i].dup = -1;
 
        ef->entries[i].fd = open(filename, O_RDWR | O_APPEND | O_CREAT, permissions);
        if (ef->entries[i].fd < 0) {
@@ -260,10 +284,7 @@ do_return:
                fr_strerror_printf("Failed to seek in file %s: %s", filename, strerror(errno));
 
        error:
-               ef->entries[i].hash = 0;
-               TALLOC_FREE(ef->entries[i].filename);
-               close(ef->entries[i].fd);
-               ef->entries[i].fd = -1;
+               exfile_cleanup_entry(&ef->entries[i]);
 
                PTHREAD_MUTEX_UNLOCK(&(ef->mutex));
                return -1;
@@ -369,7 +390,7 @@ int exfile_close(exfile_t *ef, int fd)
 
        PTHREAD_MUTEX_UNLOCK(&(ef->mutex));
 
-       fr_strerror_printf("Attempt to unlock file which does not exist");
+       fr_strerror_printf("Attempt to unlock file which is not tracked");
        return -1;
 }
 
index 230bd16..4495f72 100644 (file)
@@ -16,3 +16,7 @@ SOURCES       :=      conffile.c \
 
 # This lets the linker determine which version of the SSLeay functions to use.
 TGT_LDLIBS      := $(OPENSSL_LIBS)
+
+ifneq ($(MAKECMDGOALS),scan)
+SRC_CFLAGS     += -DBUILT_WITH_CPPFLAGS=\"$(CPPFLAGS)\" -DBUILT_WITH_CFLAGS=\"$(CFLAGS)\" -DBUILT_WITH_LDFLAGS=\"$(LDFLAGS)\" -DBUILT_WITH_LIBS=\"$(LIBS)\"
+endif
index 8ddc811..65e5c8b 100644 (file)
@@ -70,10 +70,12 @@ static void print_packet(RADIUS_PACKET *packet)
 static rad_listen_t *listen_alloc(TALLOC_CTX *ctx, RAD_LISTEN_TYPE type);
 
 #ifdef WITH_COMMAND_SOCKET
+#ifdef WITH_TCP
 static int command_tcp_recv(rad_listen_t *listener);
 static int command_tcp_send(rad_listen_t *listener, REQUEST *request);
 static int command_write_magic(int newfd, listen_socket_t *sock);
 #endif
+#endif
 
 static fr_protocol_t master_listen[];
 
@@ -766,9 +768,11 @@ int common_socket_print(rad_listen_t const *this, char *buffer, size_t bufsize)
 
        ADDSTRING(name);
 
+#ifdef WITH_TCP
        if (this->dual) {
                ADDSTRING("+acct");
        }
+#endif
 
        if (sock->interface) {
                ADDSTRING(" interface ");
@@ -1322,6 +1326,11 @@ static int auth_socket_send(rad_listen_t *listener, REQUEST *request)
                return -1;
        }
 
+       if (request->reply->data_len > (MAX_PACKET_LEN - 100)) {
+               RWARN("Packet is large, and possibly truncated - %zd vs max %d",
+                     request->reply->data_len, MAX_PACKET_LEN);
+       }
+
        return 0;
 }
 
@@ -1362,6 +1371,11 @@ static int acct_socket_send(rad_listen_t *listener, REQUEST *request)
                return -1;
        }
 
+       if (request->reply->data_len > (MAX_PACKET_LEN - 100)) {
+               RWARN("Packet is large, and possibly truncated - %zd vs max %d",
+                     request->reply->data_len, MAX_PACKET_LEN);
+       }
+
        return 0;
 }
 #endif
@@ -1384,6 +1398,11 @@ static int proxy_socket_send(rad_listen_t *listener, REQUEST *request)
                return -1;
        }
 
+       if (request->proxy->data_len > (MAX_PACKET_LEN - 100)) {
+               RWARN("Packet is large, and possibly truncated - %zd vs max %d",
+                     request->proxy->data_len, MAX_PACKET_LEN);
+       }
+
        return 0;
 }
 #endif
@@ -2095,6 +2114,11 @@ static int client_socket_encode(UNUSED rad_listen_t *listener, REQUEST *request)
                return -1;
        }
 
+       if (request->reply->data_len > (MAX_PACKET_LEN - 100)) {
+               RWARN("Packet is large, and possibly truncated - %zd vs max %d",
+                     request->reply->data_len, MAX_PACKET_LEN);
+       }
+
        if (rad_sign(request->reply, request->packet, request->client->secret) < 0) {
                RERROR("Failed signing packet: %s", fr_strerror());
 
@@ -2149,6 +2173,11 @@ static int proxy_socket_encode(UNUSED rad_listen_t *listener, REQUEST *request)
                return -1;
        }
 
+       if (request->proxy->data_len > (MAX_PACKET_LEN - 100)) {
+               RWARN("Packet is large, and possibly truncated - %zd vs max %d",
+                     request->proxy->data_len, MAX_PACKET_LEN);
+       }
+
        if (rad_sign(request->proxy, NULL, request->home_server->secret) < 0) {
                RERROR("Failed signing proxied packet: %s", fr_strerror());
 
@@ -2195,6 +2224,8 @@ static fr_protocol_t master_listen[RAD_LISTEN_MAX] = {
          common_socket_parse, common_socket_free,
          proxy_socket_recv, proxy_socket_send,
          common_socket_print, proxy_socket_encode, proxy_socket_decode },
+#else
+       { 0, "proxy", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
 #endif
 
        /* authentication */
@@ -2209,6 +2240,8 @@ static fr_protocol_t master_listen[RAD_LISTEN_MAX] = {
          common_socket_parse, common_socket_free,
          acct_socket_recv, acct_socket_send,
          common_socket_print, client_socket_encode, client_socket_decode},
+#else
+       { 0, "acct", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
 #endif
 
 #ifdef WITH_DETAIL
@@ -2219,15 +2252,11 @@ static fr_protocol_t master_listen[RAD_LISTEN_MAX] = {
          detail_print, detail_encode, detail_decode },
 #endif
 
-#ifdef WITH_VMPS
        /* vlan query protocol */
        { 0, "vmps", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-#endif
 
-#ifdef WITH_DHCP
        /* dhcp query protocol */
        { 0, "dhcp", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-#endif
 
 #ifdef WITH_COMMAND_SOCKET
        /* TCP command socket */
@@ -2235,6 +2264,8 @@ static fr_protocol_t master_listen[RAD_LISTEN_MAX] = {
          command_socket_parse, command_socket_free,
          command_domain_accept, command_domain_send,
          command_socket_print, command_socket_encode, command_socket_decode },
+#else
+       { 0, "command", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
 #endif
 
 #ifdef WITH_COA
@@ -2243,6 +2274,8 @@ static fr_protocol_t master_listen[RAD_LISTEN_MAX] = {
          common_socket_parse, NULL,
          coa_socket_recv, auth_socket_send, /* CoA packets are same as auth */
          common_socket_print, client_socket_encode, client_socket_decode },
+#else
+       { 0, "coa", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
 #endif
 
 };
@@ -3127,7 +3160,7 @@ int listen_init(CONF_SECTION *config, rad_listen_t **head, bool spawn_flag)
                override = true;
 
 #ifdef WITH_VMPS
-               if (strcmp(progname, "vmpsd") == 0) {
+               if (strcmp(main_config.name, "vmpsd") == 0) {
                        this = listen_alloc(config, RAD_LISTEN_VQP);
                        if (!auth_port) auth_port = 1589;
                } else
@@ -3167,7 +3200,7 @@ int listen_init(CONF_SECTION *config, rad_listen_t **head, bool spawn_flag)
                /*
                 *      No acct for vmpsd
                 */
-               if (strcmp(progname, "vmpsd") == 0) goto add_sockets;
+               if (strcmp(main_config.name, "vmpsd") == 0) goto add_sockets;
 #endif
 
 #ifdef WITH_ACCOUNTING
@@ -3305,7 +3338,7 @@ add_sockets:
                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 '%s -fxx -l stdout' for debugging",
-                                     progname);
+                                     main_config.name);
                        return -1;
                }
 #endif
index 3046906..43bc2b1 100644 (file)
@@ -384,12 +384,15 @@ static ssize_t xlat_client(UNUSED void *instance, REQUEST *request, char const *
 
        cp = cf_pair_find(request->client->cs, fmt);
        if (!cp || !(value = cf_pair_value(cp))) {
-               if (strcmp(fmt, "shortname") == 0) {
-                       strlcpy(out, request->client->shortname, outlen);
-                       return strlen(out);
+               if (strcmp(fmt, "shortname") == 0 && request->client->shortname) {
+                       value = request->client->shortname;
+               }
+               else if (strcmp(fmt, "nas_type") == 0 && request->client->nas_type) {
+                       value = request->client->nas_type;
+               } else {
+                       *out = '\0';
+                       return 0;
                }
-               *out = '\0';
-               return 0;
        }
 
        strlcpy(out, value, outlen);
@@ -496,7 +499,7 @@ static int switch_users(CONF_SECTION *cs)
         *      initialized.
         */
        if (fr_set_dumpable_init() < 0) {
-               fr_perror("radiusd");
+               fr_perror("%s", main_config.name);
                return 0;
        }
 
@@ -507,7 +510,8 @@ static int switch_users(CONF_SECTION *cs)
        if (rad_debug_lvl && (getuid() != 0)) return 1;
 
        if (cf_section_parse(cs, NULL, bootstrap_config) < 0) {
-               fprintf(stderr, "radiusd: Error: Failed to parse user/group information.\n");
+               fprintf(stderr, "%s: Error: Failed to parse user/group information.\n",
+                       main_config.name);
                return 0;
        }
 
@@ -523,7 +527,7 @@ static int switch_users(CONF_SECTION *cs)
                gr = getgrnam(gid_name);
                if (!gr) {
                        fprintf(stderr, "%s: Cannot get ID for group %s: %s\n",
-                               progname, gid_name, fr_syserror(errno));
+                               main_config.name, gid_name, fr_syserror(errno));
                        return 0;
                }
 
@@ -544,7 +548,7 @@ static int switch_users(CONF_SECTION *cs)
 
                if (rad_getpwnam(cs, &user, uid_name) < 0) {
                        fprintf(stderr, "%s: Cannot get passwd entry for user %s: %s\n",
-                               progname, uid_name, fr_strerror());
+                               main_config.name, uid_name, fr_strerror());
                        return 0;
                }
 
@@ -557,7 +561,7 @@ static int switch_users(CONF_SECTION *cs)
 #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, fr_syserror(errno));
+                                       main_config.name, uid_name, fr_syserror(errno));
                                talloc_free(user);
                                return 0;
                        }
@@ -573,7 +577,7 @@ static int switch_users(CONF_SECTION *cs)
        if (chroot_dir) {
                if (chroot(chroot_dir) < 0) {
                        fprintf(stderr, "%s: Failed to perform chroot %s: %s",
-                               progname, chroot_dir, fr_syserror(errno));
+                               main_config.name, chroot_dir, fr_syserror(errno));
                        return 0;
                }
 
@@ -601,7 +605,7 @@ static int switch_users(CONF_SECTION *cs)
        if (do_sgid) {
                if (setgid(server_gid) < 0){
                        fprintf(stderr, "%s: Failed setting group to %s: %s",
-                               progname, gid_name, fr_syserror(errno));
+                               main_config.name, gid_name, fr_syserror(errno));
                        return 0;
                }
        }
@@ -657,7 +661,8 @@ static int switch_users(CONF_SECTION *cs)
                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", main_config.log_file, fr_syserror(errno));
+                       fprintf(stderr, "%s: Failed to open log file %s: %s\n",
+                               main_config.name, main_config.log_file, fr_syserror(errno));
                        return 0;
                }
        }
@@ -674,7 +679,7 @@ static int switch_users(CONF_SECTION *cs)
            (default_log.dst == L_DST_FILES)) {
                if (fchown(default_log.fd, server_uid, server_gid) < 0) {
                        fprintf(stderr, "%s: Cannot change ownership of log file %s: %s\n",
-                               progname, main_config.log_file, fr_syserror(errno));
+                               main_config.name, main_config.log_file, fr_syserror(errno));
                        return 0;
                }
        }
@@ -862,13 +867,15 @@ do {\
         */
        if (default_log.dst == L_DST_NULL) {
                if (cf_section_parse(cs, NULL, startup_server_config) < 0) {
-                       fprintf(stderr, "radiusd: Error: Failed to parse log{} section.\n");
+                       fprintf(stderr, "%s: Error: Failed to parse log{} section.\n",
+                               main_config.name);
                        cf_file_free(cs);
                        return -1;
                }
 
                if (!radlog_dest) {
-                       fprintf(stderr, "radiusd: Error: No log destination specified.\n");
+                       fprintf(stderr, "%s: Error: No log destination specified.\n",
+                               main_config.name);
                        cf_file_free(cs);
                        return -1;
                }
@@ -876,8 +883,8 @@ do {\
                default_log.dst = fr_str2int(log_str2dst, radlog_dest,
                                              L_DST_NUM_DEST);
                if (default_log.dst == L_DST_NUM_DEST) {
-                       fprintf(stderr, "radiusd: Error: Unknown log_destination %s\n",
-                               radlog_dest);
+                       fprintf(stderr, "%s: Error: Unknown log_destination %s\n",
+                               main_config.name, radlog_dest);
                        cf_file_free(cs);
                        return -1;
                }
@@ -888,14 +895,15 @@ do {\
                         *      before using it
                         */
                        if (!syslog_facility) {
-                               fprintf(stderr, "radiusd: Error: Syslog chosen but no facility was specified\n");
+                               fprintf(stderr, "%s: Error: Syslog chosen but no facility was specified\n",
+                                       main_config.name);
                                cf_file_free(cs);
                                return -1;
                        }
                        main_config.syslog_facility = fr_str2int(syslog_facility_table, syslog_facility, -1);
                        if (main_config.syslog_facility < 0) {
-                               fprintf(stderr, "radiusd: Error: Unknown syslog_facility %s\n",
-                                       syslog_facility);
+                               fprintf(stderr, "%s: Error: Unknown syslog_facility %s\n",
+                                       main_config.name, syslog_facility);
                                cf_file_free(cs);
                                return -1;
                        }
@@ -905,12 +913,13 @@ do {\
                         *      Call openlog only once, when the
                         *      program starts.
                         */
-                       openlog(progname, LOG_PID, main_config.syslog_facility);
+                       openlog(main_config.name, LOG_PID, main_config.syslog_facility);
 #endif
 
                } 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");
+                               fprintf(stderr, "%s: Error: Specified \"files\" as a log destination, but no log filename was given!\n",
+                                       main_config.name);
                                cf_file_free(cs);
                                return -1;
                        }
@@ -1116,7 +1125,7 @@ static int hup_callback(void *ctx, void *data)
 
        if (!module_hup_module(mi->cs, mi, time(NULL))) return 0;
 
-       return 0;
+       return 1;
 }
 
 void main_config_hup(void)
index bbe3a63..996b790 100644 (file)
@@ -33,7 +33,7 @@ RCSID("$Id$")
 
 #include <ctype.h>
 
-#if 0
+#ifdef DEBUG_MAP
 static void map_dump(REQUEST *request, vp_map_t const *map)
 {
        RDEBUG(">>> MAP TYPES LHS: %s, RHS: %s",
@@ -1347,60 +1347,51 @@ int map_to_request(REQUEST *request, vp_map_t const *map, radius_map_getvalue_t
                break;
 
        /*
-        *      Filtering operators
+        *      Filter 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_merge(&dst_list, head);
-                       head = NULL;
-                       goto finish;
-               }
+       case T_OP_REG_NE:
+       case T_OP_NE:
+       case T_OP_REG_EQ:
+       case T_OP_CMP_EQ:
+       case T_OP_GE:
+       case T_OP_GT:
+       case T_OP_LE:
+       case T_OP_LT:
+       {
+               VALUE_PAIR *a, *b;
 
-               /*
-                *      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));
-                               fr_pair_list_free(&dst);
-                               fr_cursor_insert(&dst_list, fr_cursor_remove(&src_list));
-                               found = true;
-                               continue;
+               fr_pair_list_sort(&head, fr_pair_cmp_by_da_tag);
+               fr_pair_list_sort(list, fr_pair_cmp_by_da_tag);
 
-                       case T_OP_LE:
-                               if (rcode <= 0) continue;
-                               goto replace;
+               fr_cursor_first(&dst_list);
 
-                       case T_OP_GE:
-                               if (rcode >= 0) continue;
-                               goto replace;
+               for (b = fr_cursor_first(&src_list);
+                    b;
+                    b = fr_cursor_next(&src_list)) {
+                       for (a = fr_cursor_current(&dst_list);
+                            a;
+                            a = fr_cursor_next(&dst_list)) {
+                               int8_t cmp;
 
-                       default:
-                               fr_pair_list_free(&head);
-                               return -1;
+                               cmp = fr_pair_cmp_by_da_tag(a, b);      /* attribute and tag match */
+                               if (cmp > 0) break;
+                               else if (cmp < 0) continue;
+
+                               cmp = (value_data_cmp_op(map->op, a->da->type, &a->data, a->vp_length, b->da->type, &b->data, b->vp_length) == 0);
+                               if (cmp != 0) {
+                                       a = fr_cursor_remove(&dst_list);
+                                       talloc_free(a);
+                               }
                        }
+                       if (!a) break;  /* end of the list */
                }
                fr_pair_list_free(&head);
-               if (!found) return 0;
-
+       }
                break;
+
+       default:
+               rad_assert(0);  /* Should have been caught be the caller */
+               return -1;
        }
 
 finish:
index 00324d6..312b1bb 100644 (file)
@@ -283,9 +283,9 @@ static rlm_rcode_t CC_HINT(nonnull) call_modsingle(rlm_components_t component, m
        blocked = (request->master_state == REQUEST_STOP_PROCESSING);
        if (blocked) return RLM_MODULE_NOOP;
 
-       RDEBUG3("modsingle[%s]: calling %s (%s) for request %d",
+       RDEBUG3("modsingle[%s]: calling %s (%s)",
                comp2str[component], sp->modinst->name,
-               sp->modinst->entry->name, request->number);
+               sp->modinst->entry->name);
        request->log.indent = 0;
 
        if (sp->modinst->force) {
@@ -309,14 +309,14 @@ static rlm_rcode_t CC_HINT(nonnull) call_modsingle(rlm_components_t component, m
         */
        blocked = (request->master_state == REQUEST_STOP_PROCESSING);
        if (blocked) {
-               RWARN("Module %s became unblocked for request %u", sp->modinst->entry->name, request->number);
+               RWARN("Module %s became unblocked", sp->modinst->entry->name);
        }
 
  fail:
        request->log.indent = indent;
-       RDEBUG3("modsingle[%s]: returned from %s (%s) for request %d",
+       RDEBUG3("modsingle[%s]: returned from %s (%s)",
               comp2str[component], sp->modinst->name,
-              sp->modinst->entry->name, request->number);
+              sp->modinst->entry->name);
 
        return request->rcode;
 }
@@ -449,6 +449,10 @@ redo:
         */
        if (!c) goto finish;
 
+       if (fr_debug_lvl >= 3) {
+               VERIFY_REQUEST(request);
+       }
+
        rad_assert(c->debug_name != NULL); /* if this happens, all bets are off. */
 
        /*
@@ -514,8 +518,8 @@ redo:
                 *      Like MOD_ELSE, but allow for a later "else"
                 */
                if (if_taken) {
-                       RDEBUG2("... skipping %s for request %d: Preceding \"if\" was taken",
-                               unlang_keyword[c->type], request->number);
+                       RDEBUG2("... skipping %s: Preceding \"if\" was taken",
+                               unlang_keyword[c->type]);
                        was_if = true;
                        if_taken = true;
                        goto next_sibling;
@@ -533,14 +537,14 @@ redo:
        if (c->type == MOD_ELSE) {
                if (!was_if) { /* error */
                elsif_error:
-                       RDEBUG2("... skipping %s for request %d: No preceding \"if\"",
-                               unlang_keyword[c->type], request->number);
+                       RDEBUG2("... skipping %s: No preceding \"if\"",
+                               unlang_keyword[c->type]);
                        goto next_sibling;
                }
 
                if (if_taken) {
-                       RDEBUG2("... skipping %s for request %d: Preceding \"if\" was taken",
-                               unlang_keyword[c->type], request->number);
+                       RDEBUG2("... skipping %s: Preceding \"if\" was taken",
+                               unlang_keyword[c->type]);
                        was_if = false;
                        if_taken = false;
                        goto next_sibling;
@@ -2823,7 +2827,7 @@ static modcallable *do_compile_modgroup(modcallable *parent,
                        rad_assert(parent != NULL);
                        p = mod_callabletogroup(parent);
 
-                       rad_assert(p->tail != NULL);
+                       if (!p->tail) goto elsif_fail;
 
                        /*
                         *      We're in the process of compiling the
@@ -2833,6 +2837,7 @@ static modcallable *do_compile_modgroup(modcallable *parent,
                        f = mod_callabletogroup(p->tail);
                        if ((f->mc.type != MOD_IF) &&
                            (f->mc.type != MOD_ELSIF)) {
+                       elsif_fail:
                                cf_log_err_cs(g->cs, "Invalid location for 'elsif'.  There is no preceding 'if' statement");
                                talloc_free(g);
                                return NULL;
@@ -2863,11 +2868,12 @@ static modcallable *do_compile_modgroup(modcallable *parent,
                        rad_assert(parent != NULL);
                        p = mod_callabletogroup(parent);
 
-                       rad_assert(p->tail != NULL);
+                       if (!p->tail) goto else_fail;
 
                        f = mod_callabletogroup(p->tail);
                        if ((f->mc.type != MOD_IF) &&
                            (f->mc.type != MOD_ELSIF)) {
+                       else_fail:
                                cf_log_err_cs(g->cs, "Invalid location for 'else'.  There is no preceding 'if' statement");
                                talloc_free(g);
                                return NULL;
@@ -3776,6 +3782,12 @@ bool modcall_pass2(modcallable *mc)
                                goto do_children;
                        }
 
+                       if (g->vpt->type == TMPL_TYPE_ATTR_UNDEFINED) {
+                               if (!pass2_fixup_undefined(cf_section_to_item(g->cs), g->vpt)) {
+                                       return false;
+                               }
+                       }
+
                        /*
                         *      Compile and sanity check xlat
                         *      expansions.
@@ -3881,7 +3893,13 @@ bool modcall_pass2(modcallable *mc)
                                char const *name1 = cf_section_name1(g->cs);
 
                                if (strcmp(name1, unlang_keyword[c->type]) != 0) {
-                                       c->debug_name = talloc_asprintf(c, "%s %s", name1, cf_section_name2(g->cs));
+                                       name2 = cf_section_name2(g->cs);
+
+                                       if (!name2) {
+                                               c->debug_name = name1;
+                                       } else {
+                                               c->debug_name = talloc_asprintf(c, "%s %s", name1, name2);
+                                       }
                                }
                        }
 
@@ -3994,3 +4012,10 @@ void modcall_debug(modcallable *mc, int depth)
                }
        }
 }
+
+int modcall_pass2_condition(fr_cond_t *c)
+{
+       if (!fr_condition_walk(c, pass2_callback, NULL)) return -1;
+
+       return 0;
+}
index 6053e0e..885cbee 100644 (file)
@@ -30,6 +30,11 @@ RCSID("$Id$")
 #include <freeradius-devel/parser.h>
 #include <freeradius-devel/rad_assert.h>
 
+/** Path to search for modules in
+ *
+ */
+char const *radlib_dir = NULL;
+
 typedef struct indexed_modcallable {
        rlm_components_t        comp;
        int                     idx;
@@ -152,11 +157,11 @@ static int check_module_magic(CONF_SECTION *cs, module_t const *module)
 
 lt_dlhandle lt_dlopenext(char const *name)
 {
-       int     flags = RTLD_NOW;
-       void    *handle;
-       char    buffer[2048];
-       char    *env;
-
+       int             flags = RTLD_NOW;
+       void            *handle;
+       char            buffer[2048];
+       char            *env;
+       char const      *search_path;
 #ifdef RTLD_GLOBAL
        if (strcmp(name, "rlm_perl") == 0) {
                flags |= RTLD_GLOBAL;
@@ -170,42 +175,53 @@ lt_dlhandle lt_dlopenext(char const *name)
         */
        flags |= RTLD_NOW;
 #endif
+
+       /*
+        *      Apple removed support for DYLD_LIBRARY_PATH in rootless mode.
+        */
+       env = getenv("FR_LIBRARY_PATH");
+       if (env) {
+               DEBUG3("Ignoring libdir as FR_LIBRARY_PATH set.  Module search path will be: %s", env);
+               search_path = env;
+       } else {
+               search_path = radlib_dir;
+       }
+
        /*
         *      Prefer loading our libraries by absolute path.
         */
-       if (radlib_dir) {
+       if (search_path) {
                char *error;
+               char *ctx, *paths, *path;
+               char *p;
 
-               snprintf(buffer, sizeof(buffer), "%s/%s%s", radlib_dir, name, LT_SHREXT);
+               fr_strerror();
 
-               DEBUG4("Loading library using absolute path \"%s\"", buffer);
+               ctx = paths = talloc_strdup(NULL, search_path);
+               while ((path = strsep(&paths, ":")) != NULL) {
+                       /*
+                        *      Trim the trailing slash
+                        */
+                       p = strrchr(path, '/');
+                       if (p && ((p[1] == '\0') || (p[1] == ':'))) *p = '\0';
 
-               handle = dlopen(buffer, flags);
-               if (handle) return handle;
-               error = dlerror();
+                       path = talloc_asprintf(ctx, "%s/%s%s", path, name, LT_SHREXT);
 
-               fr_strerror_printf("%s", error);
-               DEBUG4("Failed with error: %s", error);
+                       DEBUG4("Loading %s with path: %s", name, path);
 
-               /*
-                *      Because dlopen (on OSX at least) produces really
-                *      shitty and inaccurate error messages
-                */
-               if (access(buffer, R_OK) < 0) {
-                       switch (errno) {
-                       case EACCES:
-                               WARN("Library file found, but we don't have permission to read it");
-                               break;
-
-                       case ENOENT:
-                               DEBUG4("Library file not found");
-                               break;
-
-                       default:
-                               DEBUG4("Issue accessing library file: %s", fr_syserror(errno));
-                               break;
+                       handle = dlopen(path, flags);
+                       if (handle) {
+                               talloc_free(ctx);
+                               return handle;
                        }
+                       error = dlerror();
+
+                       fr_strerror_printf("%s%s\n", fr_strerror(), error);
+                       DEBUG4("Loading %s failed: %s - %s", name, error,
+                              (access(path, R_OK) < 0) ? fr_syserror(errno) : "No access errors");
+                       talloc_free(path);
                }
+               talloc_free(ctx);
        }
 
        DEBUG4("Loading library using linker search path(s)");
@@ -415,16 +431,19 @@ static void module_instance_free(void *data)
        }
 #endif
 
-       /*
-        *      Remove any registered paircompares.
-        */
-       paircompare_unregister_instance(module->insthandle);
-
        xlat_unregister(module->name, NULL, module->insthandle);
+
        /*
         *      Remove all xlat's registered to module instance.
         */
-       if (module->insthandle) xlat_unregister_module(module->insthandle);
+       if (module->insthandle) {
+               /*
+                *      Remove any registered paircompares.
+                */
+               paircompare_unregister_instance(module->insthandle);
+
+               xlat_unregister_module(module->insthandle);
+       }
        talloc_free(module);
 }
 
@@ -622,7 +641,7 @@ static module_instance_t *module_bootstrap(CONF_SECTION *cs)
         *      section. If the CS is free'd the instance will be
         *      free'd, too.
         */
-       node = talloc_zero(cs, module_instance_t);
+       node = talloc_zero(instance_tree, module_instance_t);
        node->cs = cs;
        strlcpy(node->name, name2, sizeof(node->name));
 
@@ -1717,8 +1736,7 @@ static bool server_define_types(CONF_SECTION *cs)
         *      Loop over all of the components
         */
        for (comp = 0; comp < MOD_COUNT; ++comp) {
-               CONF_SECTION *subcs;
-               CONF_ITEM *modref;
+               CONF_SECTION *subcs, *type_cs;
                DICT_ATTR const *da;
 
                subcs = cf_section_sub_find(cs,
@@ -1741,38 +1759,74 @@ static bool server_define_types(CONF_SECTION *cs)
                /*
                 *      Define dynamic types, so that others can reference
                 *      them.
+                *
+                *      First, bare modules for 'authenticate'.
+                *      Second, Auth-Type, etc.
                 */
-               for (modref = cf_item_find_next(subcs, NULL);
-                    modref != NULL;
-                    modref = cf_item_find_next(subcs, modref)) {
-                       char const *name1;
-                       CONF_SECTION *subsubcs;
+               if (section_type_value[comp].attr == PW_AUTH_TYPE) {
+                       CONF_ITEM *modref;
 
-                       /*
-                        *      Create types for simple references
-                        *      only when parsing the authenticate
-                        *      section.
-                        */
-                       if ((section_type_value[comp].attr == PW_AUTH_TYPE) &&
-                           cf_item_is_pair(modref)) {
-                               CONF_PAIR *cp = cf_item_to_pair(modref);
+                       for (modref = cf_item_find_next(subcs, NULL);
+                            modref != NULL;
+                            modref = cf_item_find_next(subcs, modref)) {
+                               CONF_PAIR *cp;
+
+                               if (!cf_item_is_pair(modref)) continue;
+
+                               cp = cf_item_to_pair(modref);
                                if (!define_type(cs, da, cf_pair_attr(cp))) {
                                        return false;
                                }
 
-                               continue;
+                               /*
+                                *      Check for duplicates
+                                */
+                               if (rad_debug_lvl) {
+                                       CONF_PAIR *cp2;
+                                       CONF_SECTION *cs2;
+
+                                       cp2 = cf_pair_find(subcs, cf_pair_attr(cp));
+                                       rad_assert(cp2 != NULL);
+                                       if (cp2 != cp) {
+                                               WARN("%s[%d]: Duplicate module '%s'",
+                                                    cf_pair_filename(cp2),
+                                                    cf_pair_lineno(cp2),
+                                                    cf_pair_attr(cp));
+                                       }
+
+                                       cs2 = cf_section_sub_find_name2(subcs, section_type_value[comp].typename, cf_pair_attr(cp));
+                                       if (cs2) {
+                                               WARN("%s[%d]: Duplicate Auth-Type '%s'",
+                                                    cf_section_filename(cs2),
+                                                    cf_section_lineno(cs2),
+                                                    cf_pair_attr(cp));
+                                       }
+                               }
+
                        }
+               }
 
-                       if (!cf_item_is_section(modref)) continue;
+               /*
+                *      And loop over the type names
+                */
+               for (type_cs = cf_subsection_find_next(subcs, NULL, section_type_value[comp].typename);
+                    type_cs != NULL;
+                    type_cs = cf_subsection_find_next(subcs, type_cs, section_type_value[comp].typename)) {
+                       if (!define_type(cs, da, cf_section_name2(type_cs))) {
+                               return false;
+                       }
 
-                       subsubcs = cf_item_to_section(modref);
-                       name1 = cf_section_name1(subsubcs);
+                       if (rad_debug_lvl) {
+                               CONF_SECTION *cs2;
 
-                       if (strcmp(name1, section_type_value[comp].typename) == 0) {
-                         if (!define_type(cs, da,
-                                          cf_section_name2(subsubcs))) {
-                                 return false;
-                         }
+                               cs2 = cf_section_sub_find_name2(subcs, section_type_value[comp].typename, cf_section_name2(type_cs));
+                               rad_assert(cs2 != NULL);
+                               if (cs2 != type_cs) {
+                                       WARN("%s[%d]: Duplicate Auth-Type '%s'",
+                                            cf_section_filename(cs2),
+                                            cf_section_lineno(cs2),
+                                            cf_section_name2(cs2));
+                               }
                        }
                }
        } /* loop over components */
@@ -1837,8 +1891,10 @@ int modules_init(CONF_SECTION *config)
        for (cs = cf_subsection_find_next(config, NULL, "server");
             cs != NULL;
             cs = cf_subsection_find_next(config, cs, "server")) {
+#if defined(WITH_DHCP) || defined(WITH_VMPS)
                CONF_SECTION *subcs;
                DICT_ATTR const *da;
+#endif
 
 #ifdef WITH_VMPS
                /*
@@ -1902,6 +1958,8 @@ int modules_init(CONF_SECTION *config)
 
        DEBUG2("%s: #### Instantiating modules ####", main_config.name);
 
+       cf_log_info(config, " modules {");
+
        /*
         *      Loop over module definitions, looking for duplicates.
         *
@@ -1946,7 +2004,7 @@ int modules_init(CONF_SECTION *config)
                module_instance_t *module;
                char const *name;
 
-               cf_log_info(cs, " instantiate {");
+               cf_log_info(cs, "  instantiate {");
 
                /*
                 *  Loop over the items in the 'instantiate' section.
@@ -2059,7 +2117,7 @@ int modules_init(CONF_SECTION *config)
                        }  /* handle subsections */
                } /* loop over the "instantiate" section */
 
-               cf_log_info(cs, " }");
+               cf_log_info(cs, "  }");
        } /* if there's an 'instantiate' section. */
 
        /*
@@ -2068,7 +2126,6 @@ int modules_init(CONF_SECTION *config)
         *      because we've now split up the modules into
         *      mods-enabled.
         */
-       cf_log_info(cs, " modules {");
        for (ci=cf_item_find_next(modules, NULL);
             ci != NULL;
             ci=next) {
@@ -2087,7 +2144,7 @@ int modules_init(CONF_SECTION *config)
                module = module_instantiate(modules, name);
                if (!module) return -1;
        }
-       cf_log_info(cs, " } # modules");
+       cf_log_info(config, " } # modules");
 
        if (virtual_servers_load(config) < 0) return -1;
 
index c893b1e..fea349e 100644 (file)
@@ -470,7 +470,7 @@ int paircompare(REQUEST *request, VALUE_PAIR *req_list, VALUE_PAIR *check,
 {
        vp_cursor_t cursor;
        VALUE_PAIR *check_item;
-       VALUE_PAIR *auth_item;
+       VALUE_PAIR *auth_item = NULL;
        DICT_ATTR const *from;
 
        int result = 0;
@@ -533,6 +533,7 @@ int paircompare(REQUEST *request, VALUE_PAIR *req_list, VALUE_PAIR *check,
        try_again:
                if (!first_only) {
                        while (auth_item != NULL) {
+                               VERIFY_VP(auth_item);
                                if ((auth_item->da == from) || (!from)) {
                                        break;
                                }
@@ -620,6 +621,7 @@ int paircompare(REQUEST *request, VALUE_PAIR *req_list, VALUE_PAIR *check,
                 *      another of the same attribute, which DOES match.
                 */
                if ((result != 0) && (!first_only)) {
+                       fr_assert(auth_item != NULL);
                        auth_item = auth_item->next;
                        result = 0;
                        goto try_again;
index a0d3c68..5fab262 100644 (file)
@@ -436,6 +436,22 @@ static bool condition_check_types(fr_cond_t *c, PW_TYPE lhs_type)
                return true;
        }
 
+       /*
+        *      Same checks as above, but with the types swapped, and
+        *      with explicit cast for the interpretor.
+        */
+       if ((lhs_type == PW_TYPE_IPV4_ADDR) &&
+           (c->data.map->rhs->tmpl_da->type == PW_TYPE_IPV4_PREFIX)) {
+               c->cast = c->data.map->rhs->tmpl_da;
+               return true;
+       }
+
+       if ((lhs_type == PW_TYPE_IPV6_ADDR) &&
+           (c->data.map->rhs->tmpl_da->type == PW_TYPE_IPV6_PREFIX)) {
+               c->cast = c->data.map->rhs->tmpl_da;
+               return true;
+       }
+
        return false;
 }
 
@@ -1089,19 +1105,24 @@ static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *st
                                 */
                                if ((c->data.map->lhs->type == TMPL_TYPE_ATTR) &&
                                    (c->data.map->rhs->type == TMPL_TYPE_LITERAL)) {
-                                       PW_TYPE type;
+                                       PW_TYPE type = c->data.map->lhs->tmpl_da->type;
 
                                        switch (c->data.map->lhs->tmpl_da->type) {
                                        case PW_TYPE_IPV4_ADDR:
-                                               type = PW_TYPE_IPV4_PREFIX;
+                                               if (strchr(c->data.map->rhs->name, '/') != NULL) {
+                                                       type = PW_TYPE_IPV4_PREFIX;
+                                                       c->cast = dict_attrbyvalue(PW_CAST_BASE + type, 0);
+                                               }
                                                break;
 
                                        case PW_TYPE_IPV6_ADDR:
-                                               type = PW_TYPE_IPV6_PREFIX;
+                                               if (strchr(c->data.map->rhs->name, '/') != NULL) {
+                                                       type = PW_TYPE_IPV6_PREFIX;
+                                                       c->cast = dict_attrbyvalue(PW_CAST_BASE + type, 0);
+                                               }
                                                break;
 
                                        default:
-                                               type = c->data.map->lhs->tmpl_da->type;
                                                break;
                                        }
 
@@ -1149,6 +1170,23 @@ static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *st
                                } /* attr to literal comparison */
 
                                /*
+                                *      The RHS will turn into... something.  Allow for prefixes
+                                *      there, too.
+                                */
+                               if ((c->data.map->lhs->type == TMPL_TYPE_ATTR) &&
+                                   ((c->data.map->rhs->type == TMPL_TYPE_XLAT) ||
+                                    (c->data.map->rhs->type == TMPL_TYPE_XLAT_STRUCT) ||
+                                    (c->data.map->rhs->type == TMPL_TYPE_EXEC))) {
+                                       if (c->data.map->lhs->tmpl_da->type == PW_TYPE_IPV4_ADDR) {
+                                               c->cast = dict_attrbyvalue(PW_CAST_BASE + PW_TYPE_IPV4_PREFIX, 0);
+                                       }
+
+                                       if (c->data.map->lhs->tmpl_da->type == PW_TYPE_IPV6_ADDR) {
+                                               c->cast = dict_attrbyvalue(PW_CAST_BASE + PW_TYPE_IPV6_PREFIX, 0);
+                                       }
+                               }
+
+                               /*
                                 *      If the LHS is a bare word, AND it looks like
                                 *      an attribute, try to parse it as such.
                                 *
index 14cc3b0..5ec16e6 100644 (file)
@@ -350,7 +350,7 @@ void radius_update_listener(rad_listen_t *this)
 static int request_num_counter = 1;
 #ifdef WITH_PROXY
 static int request_will_proxy(REQUEST *request) CC_HINT(nonnull);
-static int request_proxy(REQUEST *request, int retransmit) CC_HINT(nonnull);
+static int request_proxy(REQUEST *request) CC_HINT(nonnull);
 STATE_MACHINE_DECL(request_ping) CC_HINT(nonnull);
 
 STATE_MACHINE_DECL(request_response_delay) CC_HINT(nonnull);
@@ -1112,7 +1112,7 @@ static void request_cleanup_delay(REQUEST *request, int action)
                        return;
                } /* else it's time to clean up */
 
-               request_done(request, REQUEST_DONE);
+               request_done(request, FR_ACTION_DONE);
                break;
 
        default:
@@ -1154,7 +1154,7 @@ static void request_response_delay(REQUEST *request, int action)
 
        switch (action) {
        case FR_ACTION_DUP:
-               ERROR("(%u) Discarding duplicate request from "
+               RDEBUG("(%u) Discarding duplicate request from "
                      "client %s port %d - ID: %u due to delayed response",
                      request->number, request->client->shortname,
                      request->packet->src_port,request->packet->id);
@@ -1541,7 +1541,7 @@ static void request_running(REQUEST *request, int action)
                         *      up the post proxy fail
                         *      handler.
                         */
-                       if (request_proxy(request, 0) < 0) goto req_finished;
+                       if (request_proxy(request) < 0) goto req_finished;
                } else
 #endif
                {
@@ -1583,14 +1583,15 @@ int request_receive(TALLOC_CTX *ctx, rad_listen_t *listener, RADIUS_PACKET *pack
 #ifdef WITH_ACCOUNTING
        if (listener->type != RAD_LISTEN_DETAIL)
 #endif
+
+#ifdef WITH_TCP
        {
                sock = listener->data;
                sock->last_packet = now.tv_sec;
 
-#ifdef WITH_TCP
                packet->proto = sock->proto;
-#endif
        }
+#endif
 
        /*
         *      Skip everything if required.
@@ -1798,7 +1799,7 @@ static REQUEST *request_setup(TALLOC_CTX *ctx, rad_listen_t *listener, RADIUS_PA
                ERROR("No memory");
                return NULL;
        }
-       request->reply = rad_alloc(request, false);
+       request->reply = rad_alloc_reply(request, packet);
        if (!request->reply) {
                ERROR("No memory");
                talloc_free(request);
@@ -2006,26 +2007,6 @@ static void tcp_socket_timer(void *ctx)
 
 #ifdef WITH_PROXY
 /*
- *     Add +/- 2s of jitter, as suggested in RFC 3539
- *     and in RFC 5080.
- */
-static void add_jitter(struct timeval *when)
-{
-       uint32_t jitter;
-
-       when->tv_sec -= 2;
-
-       jitter = fr_rand();
-       jitter ^= (jitter >> 10);
-       jitter &= ((1 << 22) - 1); /* 22 bits of 1 */
-
-       /*
-        *      Add in ~ (4 * USEC) of jitter.
-        */
-       tv_add(when, jitter);
-}
-
-/*
  *     Called by socket_del to remove requests with this socket
  */
 static int eol_proxy_listener(void *ctx, void *data)
@@ -2395,7 +2376,7 @@ static int process_proxy_reply(REQUEST *request, RADIUS_PACKET *reply)
        }
 
 #ifdef WITH_COA
-       if (request->packet->code == request->proxy->code)
+       if (request->packet->code == request->proxy->code) {
          /*
           *    Don't run the next bit if we originated a CoA
           *    packet, after receiving an Access-Request or
@@ -2403,21 +2384,30 @@ static int process_proxy_reply(REQUEST *request, RADIUS_PACKET *reply)
           */
 #endif
 
-       /*
-        *      There may NOT be a proxy reply, as we may be
-        *      running Post-Proxy-Type = Fail.
-        */
-       if (reply) {
-               fr_pair_add(&request->reply->vps, fr_pair_list_copy(request->reply, reply->vps));
-
                /*
-                *      Delete the Proxy-State Attributes from
-                *      the reply.  These include Proxy-State
-                *      attributes from us and remote server.
+                *      There may NOT be a proxy reply, as we may be
+                *      running Post-Proxy-Type = Fail.
                 */
-               fr_pair_delete_by_num(&request->reply->vps, PW_PROXY_STATE, 0, TAG_ANY);
-       }
+               if (reply) {
+                       fr_pair_add(&request->reply->vps, fr_pair_list_copy(request->reply, reply->vps));
 
+                       /*
+                        *      Delete the Proxy-State Attributes from
+                        *      the reply.  These include Proxy-State
+                        *      attributes from us and remote server.
+                        */
+                       fr_pair_delete_by_num(&request->reply->vps, PW_PROXY_STATE, 0, TAG_ANY);
+
+               } else {
+                       vp = fr_pair_find_by_num(request->config, PW_RESPONSE_PACKET_TYPE, 0, TAG_ANY);
+                       if (vp && (vp->vp_integer != 256)) {
+                               request->proxy_reply = rad_alloc_reply(request, request->proxy);
+                               request->proxy_reply->code = vp->vp_integer;
+                       }
+               }
+#ifdef WITH_COA
+       }
+#endif
        switch (rcode) {
        default:  /* Don't do anything */
                break;
@@ -2477,7 +2467,6 @@ int request_proxy_reply(RADIUS_PACKET *packet)
        }
 
        request = fr_packet2myptr(REQUEST, proxy, proxy_p);
-       request->num_proxied_responses++; /* needs to be protected by lock */
 
        PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
 
@@ -2512,12 +2501,16 @@ int request_proxy_reply(RADIUS_PACKET *packet)
         *      Status-Server packets don't count as real packets.
         */
        if (request->proxy->code != PW_CODE_STATUS_SERVER) {
+#ifdef WITH_TCP
                listen_socket_t *sock = request->proxy_listener->data;
 
-               request->home_server->last_packet_recv = now.tv_sec;
                sock->last_packet = now.tv_sec;
+#endif
+               request->home_server->last_packet_recv = now.tv_sec;
        }
 
+       request->num_proxied_responses++;
+
        /*
         *      If we have previously seen a reply, ignore the
         *      duplicate.
@@ -2568,6 +2561,8 @@ int request_proxy_reply(RADIUS_PACKET *packet)
 
 #ifdef WITH_ACCOUNTING
        case PW_CODE_ACCOUNTING_REQUEST:
+               proxy_acct_stats.last_packet = packet->timestamp.tv_sec;
+
                request->proxy_listener->stats.total_responses++;
                proxy_acct_stats.last_packet = packet->timestamp.tv_sec;
                break;
@@ -3062,6 +3057,14 @@ do_home:
 
                request->server = old_server;
        } else {
+               char buffer[128];
+
+               RDEBUG2("Starting proxy to home server %s port %d",
+                       inet_ntop(request->proxy->dst_ipaddr.af,
+                                 &request->proxy->dst_ipaddr.ipaddr,
+                                 buffer, sizeof(buffer)),
+                       request->proxy->dst_port);
+
                rcode = process_pre_proxy(pre_proxy_type, request);
        }
 
@@ -3149,7 +3152,7 @@ static int proxy_to_virtual_server(REQUEST *request)
 }
 
 
-static int request_proxy(REQUEST *request, int retransmit)
+static int request_proxy(REQUEST *request)
 {
        char buffer[128];
 
@@ -3215,11 +3218,8 @@ static int request_proxy(REQUEST *request, int retransmit)
 
        }
 
-       gettimeofday(&request->proxy_retransmit, NULL);
-       if (!retransmit) {
-               request->proxy->timestamp = request->proxy_retransmit;
-       }
-       request->home_server->last_packet_sent = request->proxy_retransmit.tv_sec;
+       gettimeofday(&request->proxy->timestamp, NULL);
+       request->home_server->last_packet_sent = request->proxy->timestamp.tv_sec;
 
        /*
         *      Encode the packet before we do anything else.
@@ -3286,7 +3286,8 @@ static int request_proxy_anew(REQUEST *request)
 
 #ifdef WITH_ACCOUNTING
        /*
-        *      Update the Acct-Delay-Time attribute.
+        *      Update the Acct-Delay-Time attribute, since the LAST
+        *      time we tried to retransmit this packet.
         */
        if (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) {
                VALUE_PAIR *vp;
@@ -3299,7 +3300,7 @@ static int request_proxy_anew(REQUEST *request)
                        struct timeval now;
 
                        gettimeofday(&now, NULL);
-                       vp->vp_integer += now.tv_sec - request->proxy_retransmit.tv_sec;
+                       vp->vp_integer += now.tv_sec - request->proxy->timestamp.tv_sec;
                }
        }
 #endif
@@ -3331,7 +3332,7 @@ static int request_proxy_anew(REQUEST *request)
        request->proxy->data = NULL;
        request->proxy->data_len = 0;
 
-       if (request_proxy(request, 1) != 1) goto post_proxy_fail;
+       if (request_proxy(request) != 1) goto post_proxy_fail;
 
        return 1;
 }
@@ -3359,6 +3360,7 @@ static void request_ping(REQUEST *request, int action)
                                 &request->proxy->dst_ipaddr.ipaddr,
                                 buffer, sizeof(buffer)),
                       request->proxy->dst_port);
+               remove_from_proxy_hash(request);
                break;
 
        case FR_ACTION_PROXY_REPLY:
@@ -3406,12 +3408,33 @@ static void request_ping(REQUEST *request, int action)
        }
 
        rad_assert(!request->in_request_hash);
+       rad_assert(!request->in_proxy_hash);
        rad_assert(request->ev == NULL);
        NO_CHILD_THREAD;
        request_done(request, FR_ACTION_DONE);
 }
 
 /*
+ *     Add +/- 2s of jitter, as suggested in RFC 3539
+ *     and in RFC 5080.
+ */
+static void add_jitter(struct timeval *when)
+{
+       uint32_t jitter;
+
+       when->tv_sec -= 2;
+
+       jitter = fr_rand();
+       jitter ^= (jitter >> 10);
+       jitter &= ((1 << 22) - 1); /* 22 bits of 1 */
+
+       /*
+        *      Add in ~ (4 * USEC) of jitter.
+        */
+       tv_add(when, jitter);
+}
+
+/*
  *     Called from start of zombie period, OR after control socket
  *     marks the home server dead.
  */
@@ -3423,9 +3446,6 @@ static void ping_home_server(void *ctx)
        struct timeval when, now;
 
        if ((home->state == HOME_STATE_ALIVE) ||
-#ifdef WITH_TCP
-           (home->proto == IPPROTO_TCP) ||
-#endif
            (home->ev != NULL)) {
                return;
        }
@@ -3479,7 +3499,8 @@ static void ping_home_server(void *ctx)
                fr_pair_make(request->proxy, &request->proxy->vps,
                         "Message-Authenticator", "0x00", T_OP_SET);
 
-       } else if (home->type == HOME_TYPE_AUTH) {
+       } else if ((home->type == HOME_TYPE_AUTH) ||
+                  (home->type == HOME_TYPE_AUTH_ACCT)) {
                request->proxy->code = PW_CODE_ACCESS_REQUEST;
 
                fr_pair_make(request->proxy, &request->proxy->vps,
@@ -3491,8 +3512,8 @@ static void ping_home_server(void *ctx)
                fr_pair_make(request->proxy, &request->proxy->vps,
                         "Message-Authenticator", "0x00", T_OP_SET);
 
-       } else {
 #ifdef WITH_ACCOUNTING
+       } else if (home->type == HOME_TYPE_ACCT) {
                request->proxy->code = PW_CODE_ACCOUNTING_REQUEST;
 
                fr_pair_make(request->proxy, &request->proxy->vps,
@@ -3504,9 +3525,14 @@ static void ping_home_server(void *ctx)
                vp = fr_pair_make(request->proxy, &request->proxy->vps,
                              "Event-Timestamp", "0", T_OP_SET);
                vp->vp_date = now.tv_sec;
-#else
-               rad_assert("Internal sanity check failed");
 #endif
+
+       } else {
+               /*
+                *      Unkown home server type.
+                */
+               talloc_free(request);
+               return;
        }
 
        vp = fr_pair_make(request->proxy, &request->proxy->vps,
@@ -3603,13 +3629,6 @@ static void mark_home_server_zombie(home_server_t *home, struct timeval *now, st
        rad_assert((home->state == HOME_STATE_ALIVE) ||
                   (home->state == HOME_STATE_UNKNOWN));
 
-#ifdef WITH_TCP
-       if (home->proto == IPPROTO_TCP) {
-               WARN("Not marking TCP server %s zombie", home->log_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
@@ -3655,10 +3674,6 @@ void revive_home_server(void *ctx)
        home_server_t *home = talloc_get_type_abort(ctx, home_server_t);
        char buffer[128];
 
-#ifdef WITH_TCP
-       rad_assert(home->proto != IPPROTO_TCP);
-#endif
-
        home->state = HOME_STATE_ALIVE;
        home->response_timeouts = 0;
        home_trigger(home, "home_server.alive");
@@ -3682,13 +3697,6 @@ 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) {
-               WARN("Not marking TCP server dead");
-               return;
-       }
-#endif
-
        PROXY( "Marking home server %s port %d as dead.",
               inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
                         buffer, sizeof(buffer)),
@@ -3808,7 +3816,7 @@ static void proxy_wait_for_reply(REQUEST *request, int action)
                 *      More than one retransmit a second is stupid,
                 *      and should be suppressed by the proxy.
                 */
-               when = request->proxy_retransmit;
+               when = request->proxy->timestamp;
                when.tv_sec++;
 
                if (timercmp(&now, &when, <)) {
@@ -3844,7 +3852,7 @@ static void proxy_wait_for_reply(REQUEST *request, int action)
                rad_assert(request->proxy_listener != NULL);
                FR_STATS_TYPE_INC(home->stats.total_requests);
                home->last_packet_sent = now.tv_sec;
-               request->proxy_retransmit = now;
+               request->proxy->timestamp = now;
                debug_packet(request, request->proxy, false);
                request->proxy_listener->send(request->proxy_listener, request);
                break;
@@ -3901,18 +3909,11 @@ static void proxy_wait_for_reply(REQUEST *request, int action)
                 *      "response_window", then mark the home server
                 *      as zombie.
                 *
-                *      If the connection is TCP, then another
-                *      "watchdog timer" function takes care of pings,
-                *      etc.  So we don't need to do it here.
-                *
                 *      This check should really be part of a home
                 *      server state machine.
                 */
                if (((home->state == HOME_STATE_ALIVE) ||
                     (home->state == HOME_STATE_UNKNOWN))
-#ifdef WITH_TCP
-                   && (home->proto != IPPROTO_TCP)
-#endif
                        ) {
                        home->response_timeouts++;
                        if (home->response_timeouts >= home->max_response_timeouts)
@@ -3930,6 +3931,17 @@ static void proxy_wait_for_reply(REQUEST *request, int action)
                        FR_STATS_TYPE_INC(proxy_acct_stats.total_timeouts);
                }
 #endif
+#ifdef WITH_COA
+               else if (home->type == HOME_TYPE_COA) {
+                       if (request->proxy_listener) FR_STATS_TYPE_INC(request->proxy_listener->stats.total_timeouts);
+
+                       if (request->packet->code == PW_CODE_COA_REQUEST) {
+                               FR_STATS_TYPE_INC(proxy_coa_stats.total_timeouts);
+                       } else {
+                               FR_STATS_TYPE_INC(proxy_dsc_stats.total_timeouts);
+                       }
+               }
+#endif
 
                /*
                 *      There was no response within the window.  Stop
@@ -4026,6 +4038,12 @@ static void request_coa_originate(REQUEST *request)
                }
        }
 
+       if (!main_config.proxy_requests) {
+               RWDEBUG("Cannot originate CoA packets unless 'proxy_requests = yes'");
+                       TALLOC_FREE(request->coa);
+               return;
+       }
+
        coa = request->coa;
 
        /*
@@ -4384,6 +4402,17 @@ static void coa_wait_for_reply(REQUEST *request, int action)
        case FR_ACTION_TIMER:
                if (request_max_time(request)) break;
 
+               /*
+                *      Don't do fail-over.  This is a 3.1 feature.
+                */
+               if (!request->home_server ||
+                   (request->home_server->state == HOME_STATE_IS_DEAD) ||
+                   !request->proxy_listener ||
+                   (request->proxy_listener->status >= RAD_LISTEN_STATUS_EOL)) {
+                       request_done(request, FR_ACTION_DONE);
+                       break;
+               }
+
                coa_retransmit(request);
                break;
 
@@ -4671,7 +4700,6 @@ static void listener_free_cb(void *ctx)
        rad_assert(this->next == NULL);
        talloc_free(this);
 }
-#endif
 
 #ifdef WITH_PROXY
 static int proxy_eol_cb(void *ctx, void *data)
@@ -4711,7 +4739,8 @@ static int proxy_eol_cb(void *ctx, void *data)
         */
        return 0;
 }
-#endif
+#endif /* WITH_PROXY */
+#endif /* WITH_TCP */
 
 static int event_new_fd(rad_listen_t *this)
 {
@@ -4794,7 +4823,7 @@ static int event_new_fd(rad_listen_t *this)
                                        rad_panic("Failed to insert event");
                                }
                        }
-#endif
+#endif /* WITH_TCP */
                        break;
 #endif /* WITH_PROXY */
 
@@ -4821,7 +4850,7 @@ static int event_new_fd(rad_listen_t *this)
                                        fr_exit(1);
                                }
                        }
-#endif
+#endif /* WITH_TCP */
                        break;
                } /* switch over listener types */
 
@@ -4898,7 +4927,7 @@ static int event_new_fd(rad_listen_t *this)
                        }
                        PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
                }
-#endif
+#endif /* WITH_PROXY */
 
                /*
                 *      Requests are still using the socket.  Wait for
@@ -4930,7 +4959,7 @@ static int event_new_fd(rad_listen_t *this)
                 */
                this->status = RAD_LISTEN_STATUS_REMOVE_NOW;
        } /* socket is at EOL */
-#endif
+#endif   /* WITH_TCP */
 
        /*
         *      Nuke the socket.
@@ -4939,8 +4968,8 @@ static int event_new_fd(rad_listen_t *this)
                int devnull;
 #ifdef WITH_TCP
                listen_socket_t *sock = this->data;
-#endif
                struct timeval when;
+#endif
 
                /*
                 *      Re-open the socket, pointing it to /dev/null.
@@ -5001,7 +5030,7 @@ static int event_new_fd(rad_listen_t *this)
                        }
                        PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
                } else
-#endif
+#endif /* WITH_PROXY */
                {
                        INFO(" ... shutting down socket %s", buffer);
 
@@ -5032,8 +5061,8 @@ static int event_new_fd(rad_listen_t *this)
                                     &(sock->ev))) {
                        rad_panic("Failed to insert event");
                }
-       }
 #endif /* WITH_TCP */
+       }
 
        return 1;
 }
@@ -5137,6 +5166,10 @@ static void handle_signal_self(int flag)
 #ifndef HAVE_PTHREAD_H
 void radius_signal_self(int flag)
 {
+       if (flag == RADIUS_SIGNAL_SELF_TERM) {
+               main_config.exiting = true;
+       }
+
        return handle_signal_self(flag);
 }
 
@@ -5151,6 +5184,10 @@ void radius_signal_self(int flag)
        ssize_t rcode;
        uint8_t buffer[16];
 
+       if (flag == RADIUS_SIGNAL_SELF_TERM) {
+               main_config.exiting = true;
+       }
+
        /*
         *      The read MUST be non-blocking for this to work.
         */
index 016e560..7594ed4 100644 (file)
@@ -635,10 +635,8 @@ static int radclient_init(TALLOC_CTX *ctx, rc_file_pair_t *files)
                                        break;
 
                                default:
-                                       REDEBUG("Can't determine expected response to Status-Server request, specify "
-                                               "a well known RADIUS port, or add a Response-Packet-Type attribute "
-                                               "to the request of filter");
-                                       goto error;
+                                       request->filter_code = PW_CODE_UNDEFINED;
+                                       break;
                                }
                                break;
 
@@ -1114,7 +1112,7 @@ static int recv_one_packet(int wait_time)
         *      If we had an expected response code, check to see if the
         *      packet matched that.
         */
-       if (request->reply->code != request->filter_code) {
+       if ((request->filter_code != PW_CODE_UNDEFINED) && (request->reply->code != request->filter_code)) {
                if (is_radius_code(request->reply->code)) {
                        REDEBUG("%s: Expected %s got %s", request->name, fr_packet_codes[request->filter_code],
                                fr_packet_codes[request->reply->code]);
index 99ee4b5..9f190cb 100644 (file)
@@ -54,10 +54,9 @@ RCSID("$Id$")
 /*
  *  Global variables.
  */
-char const     *progname = NULL;
 char const     *radacct_dir = NULL;
 char const     *radlog_dir = NULL;
-char const     *radlib_dir = NULL;
+
 bool           log_stripped_names;
 
 char const *radiusd_version = "FreeRADIUS Version " RADIUSD_VERSION_STRING
@@ -94,6 +93,7 @@ int main(int argc, char *argv[])
        bool display_version = false;
        int flag = 0;
        int from_child[2] = {-1, -1};
+       char *p;
        fr_state_t *state = NULL;
 
        /*
@@ -107,16 +107,12 @@ int main(int argc, char *argv[])
        set_auth_parameters(argc, argv);
 #endif
 
-       if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL)
-               progname = argv[0];
-       else
-               progname++;
-
 #ifdef WIN32
        {
                WSADATA wsaData;
                if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
-                       fprintf(stderr, "%s: Unable to initialize socket library.\n", progname);
+                       fprintf(stderr, "%s: Unable to initialize socket library.\n",
+                               main_config.name);
                        exit(EXIT_FAILURE);
                }
        }
@@ -131,9 +127,15 @@ int main(int argc, char *argv[])
        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;
 
+       p = strrchr(argv[0], FR_DIR_SEP);
+       if (!p) {
+               main_config.name = argv[0];
+       } else {
+               main_config.name = p + 1;
+       }
+
        /*
         *      Don't put output anywhere until we get told a little
         *      more.
@@ -177,7 +179,8 @@ int main(int argc, char *argv[])
                                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", main_config.log_file, fr_syserror(errno));
+                                       fprintf(stderr, "%s: Failed to open log file %s: %s\n",
+                                               main_config.name, main_config.log_file, fr_syserror(errno));
                                        exit(EXIT_FAILURE);
                                }
                                fr_log_fp = fdopen(default_log.fd, "a");
@@ -185,7 +188,8 @@ int main(int argc, char *argv[])
 
                        case 'i':
                                if (ip_hton(&main_config.myip, AF_UNSPEC, optarg, false) < 0) {
-                                       fprintf(stderr, "radiusd: Invalid IP Address or hostname \"%s\"\n", optarg);
+                                       fprintf(stderr, "%s: Invalid IP Address or hostname \"%s\"\n",
+                                               main_config.name, optarg);
                                        exit(EXIT_FAILURE);
                                }
                                flag |= 1;
@@ -210,7 +214,8 @@ int main(int argc, char *argv[])
 
                                port = strtoul(optarg, 0, 10);
                                if ((port == 0) || (port > UINT16_MAX)) {
-                                       fprintf(stderr, "radiusd: Invalid port number \"%s\"\n", optarg);
+                                       fprintf(stderr, "%s: Invalid port number \"%s\"\n",
+                                               main_config.name, optarg);
                                        exit(EXIT_FAILURE);
                                }
 
@@ -264,7 +269,7 @@ int main(int argc, char *argv[])
         *  Mismatch between the binary and the libraries it depends on.
         */
        if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
-               fr_perror("radiusd");
+               fr_perror("%s", main_config.name);
                exit(EXIT_FAILURE);
        }
 
@@ -279,7 +284,8 @@ int main(int argc, char *argv[])
 #endif
 
        if (flag && (flag != 0x03)) {
-               fprintf(stderr, "radiusd: The options -i and -p cannot be used individually.\n");
+               fprintf(stderr, "%s: The options -i and -p cannot be used individually.\n",
+                       main_config.name);
                exit(EXIT_FAILURE);
        }
 
@@ -291,7 +297,8 @@ int main(int argc, char *argv[])
         */
        if (main_config.memory_report) {
                if (spawn_flag) {
-                       fprintf(stderr, "radiusd: The server cannot produce memory reports (-M) in threaded mode\n");
+                       fprintf(stderr, "%s: The server cannot produce memory reports (-M) in threaded mode\n",
+                               main_config.name);
                        exit(EXIT_FAILURE);
                }
                talloc_enable_null_tracking();
@@ -303,13 +310,12 @@ int main(int argc, char *argv[])
         *  Better here, so it doesn't matter whether we get passed -xv or -vx.
         */
        if (display_version) {
-               /* Don't print timestamps */
-               rad_debug_lvl += 2;
+               if (rad_debug_lvl == 0) rad_debug_lvl = 1;
                fr_log_fp = stdout;
                default_log.dst = L_DST_STDOUT;
                default_log.fd = STDOUT_FILENO;
 
-               INFO("%s: %s", progname, radiusd_version);
+               INFO("%s: %s", main_config.name, radiusd_version);
                version_print();
                exit(EXIT_SUCCESS);
        }
@@ -364,7 +370,7 @@ int main(int argc, char *argv[])
                if (!panic_action) panic_action = main_config.panic_action;
 
                if (panic_action && (fr_fault_setup(panic_action, argv[0]) < 0)) {
-                       fr_perror("radiusd");
+                       fr_perror("%s", main_config.name);
                        exit(EXIT_FAILURE);
                }
        }
@@ -661,7 +667,7 @@ static void NEVER_RETURNS usage(int status)
 {
        FILE *output = status?stderr:stdout;
 
-       fprintf(output, "Usage: %s [options]\n", progname);
+       fprintf(output, "Usage: %s [options]\n", main_config.name);
        fprintf(output, "Options:\n");
        fprintf(output, "  -C            Check configuration and exit.\n");
        fprintf(stderr, "  -d <raddb>    Set configuration directory (defaults to " RADDBDIR ").\n");
index 116ff91..83d7dc7 100644 (file)
@@ -9,9 +9,6 @@ SOURCES += cb.c tls.c tls_listen.c
 endif
 
 SRC_CFLAGS     := -DHOSTINFO=\"${HOSTINFO}\"
-ifneq ($(MAKECMDGOALS),scan)
-SRC_CFLAGS     += -DBUILT_WITH_CPPFLAGS=\"$(CPPFLAGS)\" -DBUILT_WITH_CFLAGS=\"$(CFLAGS)\" -DBUILT_WITH_LDFLAGS=\"$(LDFLAGS)\" -DBUILT_WITH_LIBS=\"$(LIBS)\"
-endif
 
 TGT_INSTALLDIR  := ${sbindir}
 TGT_LDLIBS     := $(LIBS) $(OPENSSL_LIBS) $(LCRYPT)
index 3823c96..766ce1f 100644 (file)
@@ -1,5 +1,5 @@
-install: install.bindir $(R)$(bindir)/radlast
+install: $(R)$(bindir)/radlast
 
-$(R)$(bindir)/radlast: src/main/radlast
+$(R)$(bindir)/radlast: src/main/radlast | $(R)$(bindir)
        @echo INSTALL $(notdir $<)
        @$(INSTALL) -m 755 $< $(R)$(bindir)
index 5834078..5792fdd 100644 (file)
@@ -64,7 +64,7 @@ RCSID("$Id$")
 /*
  *     For configuration file stuff.
  */
-char const *progname = "radmin";
+static char const *progname = "radmin";
 static char const *radmin_version = "radmin version " RADIUSD_VERSION_STRING
 #ifdef RADIUSD_VERSION_COMMIT
 " (git #" STRINGIFY(RADIUSD_VERSION_COMMIT) ")"
@@ -603,7 +603,7 @@ int main(int argc, char **argv)
 
        if (!quiet) {
                printf("%s - FreeRADIUS Server administration tool.\n", radmin_version);
-               printf("Copyright (C) 2008-2015 The FreeRADIUS server project and contributors.\n");
+               printf("Copyright (C) 2008-2016 The FreeRADIUS server project and contributors.\n");
                printf("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n");
                printf("PARTICULAR PURPOSE.\n");
                printf("You may redistribute copies of FreeRADIUS under the terms of the\n");
index 375fe26..2e5c486 100644 (file)
@@ -1094,12 +1094,22 @@ static void rs_packet_process(uint64_t count, rs_event_t *event, struct pcap_pkt
                                diff, udp_len);
                        return;
                }
-               /* Trailing data */
+
+#if 0
+               /*
+                *      It seems many probes add trailing garbage to the end
+                *      of each capture frame.  This has been observed with
+                *      the F5 and Netscout.
+                *
+                *      Leaving the code here in case it's ever needed for
+                *      debugging.
+                */
                else if (diff < 0) {
                        REDEBUG("Packet too big by %zi bytes, UDP header + Payload should be %hu bytes",
                                diff * -1, udp_len);
                        return;
                }
+#endif
        }
        if ((version == 4) && conf->verify_udp_checksum) {
                uint16_t expected;
index 1941997..3adc133 100644 (file)
@@ -1,5 +1,5 @@
-install: install.bindir $(R)$(bindir)/radtest
+install: $(R)$(bindir)/radtest
 
-$(R)$(bindir)/radtest: src/main/radtest
+$(R)$(bindir)/radtest: src/main/radtest | $(R)$(bindir)
        @echo INSTALL $(notdir $<)
        @$(INSTALL) -m 755 $< $(R)$(bindir)
index 29c1a34..e169a47 100644 (file)
@@ -45,7 +45,7 @@ static char const *eol = "\n";
 static int showname = -1;
 static int showptype = 0;
 static int showcid = 0;
-char const *progname = "radwho";
+static char const *progname = "radwho";
 char const *radlog_dir = NULL;
 
 static char const *radutmp_file = NULL;
@@ -53,7 +53,6 @@ static char const *raddb_dir = RADDBDIR;
 static char const *dict_dir = DICTDIR;
 
 char const *radacct_dir = NULL;
-char const *radlib_dir = NULL;
 
 bool log_stripped_names;
 
index 44d8d4a..bd0eb6d 100644 (file)
@@ -1,5 +1,5 @@
-install: install.bindir $(R)$(bindir)/radzap
+install: $(R)$(bindir)/radzap
 
-$(R)$(bindir)/radzap: src/main/radzap
+$(R)$(bindir)/radzap: src/main/radzap | $(R)$(bindir)
        @echo INSTALL $(notdir $<)
        @$(INSTALL) -m 755 $< $(R)$(bindir)
index 3ed4686..738e69a 100644 (file)
@@ -234,6 +234,31 @@ static ssize_t CC_HINT(nonnull) xlat_home_server(UNUSED void *instance, REQUEST
                return 0;
        }
 
+       if (strcmp(fmt, "state") == 0) {
+               char const *state;
+
+               switch (request->home_server->state) {
+               case HOME_STATE_ALIVE:
+                       state = "alive";
+                       break;
+
+               case HOME_STATE_ZOMBIE:
+                       state = "zombie";
+                       break;
+
+               case HOME_STATE_IS_DEAD:
+                       state = "dead";
+                       break;
+
+               default:
+                       state = "unknown";
+                       break;
+               }
+
+               strlcpy(out, state, outlen);
+               return strlen(out);
+       }
+
        return xlat_cs(request->home_server->cs, fmt, out, outlen);
 }
 
@@ -251,6 +276,20 @@ static ssize_t CC_HINT(nonnull) xlat_server_pool(UNUSED void *instance, REQUEST
                return 0;
        }
 
+       if (strcmp(fmt, "state") == 0) {
+               char const *state;
+
+               if (request->home_pool->in_fallback) {
+                       state = "fallback";
+
+               } else {
+                       state = "alive";
+               }
+
+               strlcpy(out, state, outlen);
+               return strlen(out);
+       }
+
        return xlat_cs(request->home_pool->cs, fmt, out, outlen);
 }
 #endif
@@ -683,7 +722,8 @@ home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SE
                                goto error;
                        }
 
-                       if ((home->type == HOME_TYPE_AUTH) && !home->ping_user_password) {
+                       if (((home->type == HOME_TYPE_AUTH) ||
+                            (home->type == HOME_TYPE_AUTH_ACCT)) && !home->ping_user_password) {
                                cf_log_err_cs(cs, "You must supply a 'password' to enable status_check=request");
                                goto error;
                        }
@@ -903,7 +943,7 @@ CONF_SECTION *home_server_cs_afrom_client(CONF_SECTION *client)
        if (cs) {
                server = cf_section_dup(client, cs, "home_server", NULL, true);
        } else {
-               server = cf_section_alloc(client, "home_server", NULL);
+               server = cf_section_alloc(client, "home_server", cf_section_name2(client));
        }
 
        if (!cs || (!cf_pair_find(cs, "ipaddr") && !cf_pair_find(cs, "ipv4addr") && !cf_pair_find(cs, "ipv6addr"))) {
@@ -2652,7 +2692,11 @@ home_server_t *home_server_ldb(char const *realmname,
 }
 
 
-home_server_t *home_server_find(fr_ipaddr_t *ipaddr, uint16_t port, int proto)
+home_server_t *home_server_find(fr_ipaddr_t *ipaddr, uint16_t port,
+#ifndef WITH_TCP
+                               UNUSED
+#endif
+                               int proto)
 {
        home_server_t myhome;
 
index 6e0d31c..e359010 100644 (file)
@@ -40,7 +40,7 @@ int session_zap(REQUEST *request, uint32_t nasaddr, uint32_t nas_port,
                int session_time)
 {
        REQUEST *stopreq;
-       VALUE_PAIR *vp, *userpair;
+       VALUE_PAIR *vp;
        int ret;
 
        stopreq = request_alloc_fake(request);
@@ -54,7 +54,6 @@ int session_zap(REQUEST *request, uint32_t nasaddr, uint32_t nas_port,
                if(!(vp = fr_pair_afrom_num(stopreq->packet,n, 0))) {   \
                        talloc_free(stopreq); \
                        ERROR("no memory"); \
-                       fr_pair_list_free(&(stopreq->packet->vps)); \
                        return 0; \
                } \
                vp->e = v; \
@@ -69,7 +68,6 @@ int session_zap(REQUEST *request, uint32_t nasaddr, uint32_t nas_port,
          if(!(vp = fr_pair_afrom_num(stopreq->packet,n, 0))) { \
                talloc_free(stopreq); \
                ERROR("no memory"); \
-               fr_pair_list_free(&(stopreq->packet->vps)); \
                return 0; \
        } \
        fr_pair_value_strcpy(vp, v);    \
@@ -78,9 +76,14 @@ int session_zap(REQUEST *request, uint32_t nasaddr, uint32_t nas_port,
 
        INTPAIR(PW_ACCT_STATUS_TYPE, PW_STATUS_STOP);
        IPPAIR(PW_NAS_IP_ADDRESS, nasaddr);
+
+       INTPAIR(PW_EVENT_TIMESTAMP, 0);
+       vp->vp_date = time(NULL);
        INTPAIR(PW_ACCT_DELAY_TIME, 0);
+
        STRINGPAIR(PW_USER_NAME, user);
-       userpair = vp;
+       stopreq->username = vp;
+
        INTPAIR(PW_NAS_PORT, nas_port);
        STRINGPAIR(PW_ACCT_SESSION_ID, sessionid);
        if(proto == 'P') {
@@ -100,9 +103,10 @@ int session_zap(REQUEST *request, uint32_t nasaddr, uint32_t nas_port,
        INTPAIR(PW_ACCT_INPUT_PACKETS, 0);
        INTPAIR(PW_ACCT_OUTPUT_PACKETS, 0);
 
-       stopreq->username = userpair;
        stopreq->password = NULL;
 
+       RDEBUG("Running Accounting section for automatically created accounting 'stop'");
+       rdebug_pair_list(L_DBG_LVL_1, request, request->packet->vps, NULL);
        ret = rad_accounting(stopreq);
 
        /*
index ab2bad0..754ad84 100644 (file)
@@ -145,7 +145,6 @@ static int eapsoh_mstlv(REQUEST *request, uint8_t const *p, unsigned int data_le
        VALUE_PAIR *vp;
        uint8_t c;
        int t;
-       char *q;
 
        while (data_len > 0) {
                c = *p++;
@@ -248,11 +247,7 @@ static int eapsoh_mstlv(REQUEST *request, uint8_t const *p, unsigned int data_le
                        vp = pair_make_request("SoH-MS-Machine-Name", NULL, T_OP_EQ);
                        if (!vp) return 0;
 
-                       vp->vp_strvalue = q = talloc_array(vp, char, t);
-                       vp->type = VT_DATA;
-
-                       memcpy(q, p, t);
-                       q[t] = 0;
+                       fr_pair_value_bstrncpy(vp, p, t);
 
                        p += t;
                        data_len -= 2 + t;
index e292e04..161834e 100644 (file)
@@ -39,7 +39,8 @@ typedef struct state_entry_t {
 
        int             tries;
 
-       VALUE_PAIR      *vps;
+       TALLOC_CTX              *ctx;
+       VALUE_PAIR              *vps;
 
        void            *opaque;
        void            (*free_opaque)(void *opaque);
@@ -125,6 +126,9 @@ static void state_entry_free(fr_state_t *state, state_entry_t *entry)
        (void) talloc_get_type_abort(entry, state_entry_t);
 #endif
        rbtree_deletebydata(state->tree, entry);
+
+       if (entry->ctx) talloc_free(entry->ctx);
+
        talloc_free(entry);
 }
 
@@ -180,7 +184,7 @@ void fr_state_delete(fr_state_t *state)
 /*
  *     Create a new entry.  Called with the mutex held.
  */
-static state_entry_t *fr_state_create(fr_state_t *state, RADIUS_PACKET *packet, state_entry_t *old)
+static state_entry_t *fr_state_create(fr_state_t *state, const char *server, RADIUS_PACKET *packet, state_entry_t *old)
 {
        size_t i;
        uint32_t x;
@@ -208,7 +212,7 @@ static state_entry_t *fr_state_create(fr_state_t *state, RADIUS_PACKET *packet,
                 *      Unused.  We can delete it, even if now isn't
                 *      the time to clean it up.
                 */
-               if (!entry->vps && !entry->opaque) {
+               if (!entry->ctx && !entry->opaque) {
                        state_entry_free(state, entry);
                        continue;
                }
@@ -252,8 +256,6 @@ static state_entry_t *fr_state_create(fr_state_t *state, RADIUS_PACKET *packet,
        if (old) {
                entry->tries = old->tries + 1;
 
-               rad_assert(old->vps == NULL);
-
                /*
                 *      Track State
                 */
@@ -299,6 +301,10 @@ static state_entry_t *fr_state_create(fr_state_t *state, RADIUS_PACKET *packet,
                fr_pair_add(&packet->vps, vp);
        }
 
+       /*      Make unique for different virtual servers handling same request
+        */
+       if (server) *((uint32_t *)(&entry->state[4])) ^= fr_hash_string(server);
+
        if (!rbtree_insert(state->tree, entry)) {
                talloc_free(entry);
                return NULL;
@@ -328,7 +334,7 @@ static state_entry_t *fr_state_create(fr_state_t *state, RADIUS_PACKET *packet,
 /*
  *     Find the entry, based on the State attribute.
  */
-static state_entry_t *fr_state_find(fr_state_t *state, RADIUS_PACKET *packet)
+static state_entry_t *fr_state_find(fr_state_t *state, const char *server, RADIUS_PACKET *packet)
 {
        VALUE_PAIR *vp;
        state_entry_t *entry, my_entry;
@@ -340,6 +346,10 @@ static state_entry_t *fr_state_find(fr_state_t *state, RADIUS_PACKET *packet)
 
        memcpy(my_entry.state, vp->vp_octets, sizeof(my_entry.state));
 
+       /*      Make unique for different virtual servers handling same request
+        */
+       if (server) *((uint32_t *)(&my_entry.state[4])) ^= fr_hash_string(server);
+
        entry = rbtree_finddata(state->tree, &my_entry);
 
 #ifdef WITH_VERIFY_PTR
@@ -362,7 +372,7 @@ void fr_state_discard(REQUEST *request, RADIUS_PACKET *original)
        request->state = NULL;
 
        PTHREAD_MUTEX_LOCK(&state->mutex);
-       entry = fr_state_find(state, original);
+       entry = fr_state_find(state, request->server, original);
        if (!entry) {
                PTHREAD_MUTEX_UNLOCK(&state->mutex);
                return;
@@ -380,6 +390,7 @@ void fr_state_get_vps(REQUEST *request, RADIUS_PACKET *packet)
 {
        state_entry_t *entry;
        fr_state_t *state = &global_state;
+       TALLOC_CTX *old_ctx = NULL;
 
        rad_assert(request->state == NULL);
 
@@ -392,16 +403,24 @@ void fr_state_get_vps(REQUEST *request, RADIUS_PACKET *packet)
        }
 
        PTHREAD_MUTEX_LOCK(&state->mutex);
-       entry = fr_state_find(state, packet);
+       entry = fr_state_find(state, request->server, packet);
 
        /*
         *      This has to be done in a mutex lock, because talloc
         *      isn't thread-safe.
         */
        if (entry) {
-               fr_pair_list_mcopy_by_num(request, &request->state, &entry->vps, 0, 0, TAG_ANY);
-               RDEBUG2("session-state: Found cached attributes");
-               rdebug_pair_list(L_DBG_LVL_1, request, request->state, NULL);
+               RDEBUG2("Restoring &session-state");
+
+               if (request->state_ctx) old_ctx = request->state_ctx;
+
+               request->state_ctx = entry->ctx;
+               request->state = entry->vps;
+
+               entry->ctx = NULL;
+               entry->vps = NULL;
+
+               rdebug_pair_list(L_DBG_LVL_2, request, request->state, "&session-state:");
 
        } else {
                RDEBUG2("session-state: No cached attributes");
@@ -409,6 +428,11 @@ void fr_state_get_vps(REQUEST *request, RADIUS_PACKET *packet)
 
        PTHREAD_MUTEX_UNLOCK(&state->mutex);
 
+       /*
+        *      Free this outside of the mutex for less contention.
+        */
+       if (old_ctx) talloc_free(old_ctx);
+
        VERIFY_REQUEST(request);
        return;
 }
@@ -435,22 +459,24 @@ bool fr_state_put_vps(REQUEST *request, RADIUS_PACKET *original, RADIUS_PACKET *
        PTHREAD_MUTEX_LOCK(&state->mutex);
 
        if (original) {
-               old = fr_state_find(state, original);
+               old = fr_state_find(state, request->server, original);
        } else {
                old = NULL;
        }
 
-       entry = fr_state_create(state, packet, old);
+       entry = fr_state_create(state, request->server, packet, old);
        if (!entry) {
                PTHREAD_MUTEX_UNLOCK(&state->mutex);
                return false;
        }
 
-       /*
-        *      This has to be done in a mutex lock, because talloc
-        *      isn't thread-safe.
-        */
-       fr_pair_list_mcopy_by_num(entry, &entry->vps, &request->state, 0, 0, TAG_ANY);
+       rad_assert(entry->ctx == NULL);
+       entry->ctx = request->state_ctx;
+       entry->vps = request->state;
+
+       request->state_ctx = NULL;
+       request->state = NULL;
+
        PTHREAD_MUTEX_UNLOCK(&state->mutex);
 
        rad_assert(request->state == NULL);
@@ -462,7 +488,7 @@ bool fr_state_put_vps(REQUEST *request, RADIUS_PACKET *original, RADIUS_PACKET *
  *     Find the opaque data associated with a State attribute.
  *     Leave the data in the entry.
  */
-void *fr_state_find_data(fr_state_t *state, UNUSED REQUEST *request, RADIUS_PACKET *packet)
+void *fr_state_find_data(fr_state_t *state, REQUEST *request, RADIUS_PACKET *packet)
 {
        void *data;
        state_entry_t *entry;
@@ -470,7 +496,7 @@ void *fr_state_find_data(fr_state_t *state, UNUSED REQUEST *request, RADIUS_PACK
        if (!state) return false;
 
        PTHREAD_MUTEX_LOCK(&state->mutex);
-       entry = fr_state_find(state, packet);
+       entry = fr_state_find(state, request->server, packet);
        if (!entry) {
                PTHREAD_MUTEX_UNLOCK(&state->mutex);
                return NULL;
@@ -487,7 +513,7 @@ void *fr_state_find_data(fr_state_t *state, UNUSED REQUEST *request, RADIUS_PACK
  *     Get the opaque data associated with a State attribute.
  *     and remove the data from the entry.
  */
-void *fr_state_get_data(fr_state_t *state, UNUSED REQUEST *request, RADIUS_PACKET *packet)
+void *fr_state_get_data(fr_state_t *state, REQUEST *request, RADIUS_PACKET *packet)
 {
        void *data;
        state_entry_t *entry;
@@ -495,7 +521,7 @@ void *fr_state_get_data(fr_state_t *state, UNUSED REQUEST *request, RADIUS_PACKE
        if (!state) return NULL;
 
        PTHREAD_MUTEX_LOCK(&state->mutex);
-       entry = fr_state_find(state, packet);
+       entry = fr_state_find(state, request->server, packet);
        if (!entry) {
                PTHREAD_MUTEX_UNLOCK(&state->mutex);
                return NULL;
@@ -513,7 +539,7 @@ void *fr_state_get_data(fr_state_t *state, UNUSED REQUEST *request, RADIUS_PACKE
  *     Get the opaque data associated with a State attribute.
  *     and remove the data from the entry.
  */
-bool fr_state_put_data(fr_state_t *state, UNUSED REQUEST *request, RADIUS_PACKET *original, RADIUS_PACKET *packet,
+bool fr_state_put_data(fr_state_t *state, REQUEST *request, RADIUS_PACKET *original, RADIUS_PACKET *packet,
                       void *data, void (*free_data)(void *))
 {
        state_entry_t *entry, *old;
@@ -523,12 +549,12 @@ bool fr_state_put_data(fr_state_t *state, UNUSED REQUEST *request, RADIUS_PACKET
        PTHREAD_MUTEX_LOCK(&state->mutex);
 
        if (original) {
-               old = fr_state_find(state, original);
+               old = fr_state_find(state, request->server, original);
        } else {
                old = NULL;
        }
 
-       entry = fr_state_create(state, packet, old);
+       entry = fr_state_create(state, request->server, packet, old);
        if (!entry) {
                PTHREAD_MUTEX_UNLOCK(&state->mutex);
                return false;
index 7f85718..8305e44 100644 (file)
@@ -58,7 +58,6 @@ fr_stats_t proxy_dsc_stats = FR_STATS_INIT;
 #endif
 #endif
 
-
 static void tv_sub(struct timeval *end, struct timeval *start,
                   struct timeval *elapsed)
 {
@@ -131,7 +130,6 @@ void request_stats_final(REQUEST *request)
 #undef INC_AUTH
 #define INC_AUTH(_x) radius_auth_stats._x++;request->listener->stats._x++;request->client->auth._x++;
 
-
 #undef INC_ACCT
 #ifdef WITH_ACCOUNTING
 #define INC_ACCT(_x) radius_acct_stats._x++;request->listener->stats._x++;request->client->acct._x++
@@ -265,19 +263,19 @@ void request_stats_final(REQUEST *request)
 
 #ifdef WITH_ACCOUNTING
        case PW_CODE_ACCOUNTING_REQUEST:
-               proxy_acct_stats.total_requests++;
+               proxy_acct_stats.total_requests += request->num_proxied_requests;
                request->home_server->stats.total_requests += request->num_proxied_requests;
                break;
 #endif
 
 #ifdef WITH_COA
        case PW_CODE_COA_REQUEST:
-               proxy_coa_stats.total_requests++;
+               proxy_coa_stats.total_requests += request->num_proxied_requests;
                request->home_server->stats.total_requests += request->num_proxied_requests;
                break;
 
        case PW_CODE_DISCONNECT_REQUEST:
-               proxy_dsc_stats.total_requests++;
+               proxy_dsc_stats.total_requests += request->num_proxied_requests;
                request->home_server->stats.total_requests += request->num_proxied_requests;
                break;
 #endif
@@ -330,7 +328,7 @@ void request_stats_final(REQUEST *request)
        case PW_CODE_COA_NAK:
                proxy_coa_stats.total_responses++;
                request->home_server->stats.total_responses++;
-               stats_time(&proxy_acct_stats,
+               stats_time(&proxy_coa_stats,
                           &request->proxy->timestamp,
                           &request->proxy_reply->timestamp);
                stats_time(&request->home_server->stats,
@@ -340,9 +338,9 @@ void request_stats_final(REQUEST *request)
 
        case PW_CODE_DISCONNECT_ACK:
        case PW_CODE_DISCONNECT_NAK:
-               proxy_coa_stats.total_responses++;
+               proxy_dsc_stats.total_responses++;
                request->home_server->stats.total_responses++;
-               stats_time(&proxy_acct_stats,
+               stats_time(&proxy_dsc_stats,
                           &request->proxy->timestamp,
                           &request->proxy_reply->timestamp);
                stats_time(&request->home_server->stats,
@@ -372,16 +370,16 @@ typedef struct fr_stats2vp {
  *     Authentication
  */
 static fr_stats2vp authvp[] = {
-       { 128, offsetof(fr_stats_t, total_requests) },
-       { 129, offsetof(fr_stats_t, total_access_accepts) },
-       { 130, offsetof(fr_stats_t, total_access_rejects) },
-       { 131, offsetof(fr_stats_t, total_access_challenges) },
-       { 132, offsetof(fr_stats_t, total_responses) },
-       { 133, offsetof(fr_stats_t, total_dup_requests) },
-       { 134, offsetof(fr_stats_t, total_malformed_requests) },
-       { 135, offsetof(fr_stats_t, total_bad_authenticators) },
-       { 136, offsetof(fr_stats_t, total_packets_dropped) },
-       { 137, offsetof(fr_stats_t, total_unknown_types) },
+       { PW_FREERADIUS_TOTAL_ACCESS_REQUESTS, offsetof(fr_stats_t, total_requests) },
+       { PW_FREERADIUS_TOTAL_ACCESS_ACCEPTS, offsetof(fr_stats_t, total_access_accepts) },
+       { PW_FREERADIUS_TOTAL_ACCESS_REJECTS, offsetof(fr_stats_t, total_access_rejects) },
+       { PW_FREERADIUS_TOTAL_ACCESS_CHALLENGES, offsetof(fr_stats_t, total_access_challenges) },
+       { PW_FREERADIUS_TOTAL_AUTH_RESPONSES, offsetof(fr_stats_t, total_responses) },
+       { PW_FREERADIUS_TOTAL_AUTH_DUPLICATE_REQUESTS, offsetof(fr_stats_t, total_dup_requests) },
+       { PW_FREERADIUS_TOTAL_AUTH_MALFORMED_REQUESTS, offsetof(fr_stats_t, total_malformed_requests) },
+       { PW_FREERADIUS_TOTAL_AUTH_INVALID_REQUESTS, offsetof(fr_stats_t, total_bad_authenticators) },
+       { PW_FREERADIUS_TOTAL_AUTH_DROPPED_REQUESTS, offsetof(fr_stats_t, total_packets_dropped) },
+       { PW_FREERADIUS_TOTAL_AUTH_UNKNOWN_TYPES, offsetof(fr_stats_t, total_unknown_types) },
        { 0, 0 }
 };
 
@@ -391,16 +389,16 @@ static fr_stats2vp authvp[] = {
  *     Proxied authentication requests.
  */
 static fr_stats2vp proxy_authvp[] = {
-       { 138, offsetof(fr_stats_t, total_requests) },
-       { 139, offsetof(fr_stats_t, total_access_accepts) },
-       { 140, offsetof(fr_stats_t, total_access_rejects) },
-       { 141, offsetof(fr_stats_t, total_access_challenges) },
-       { 142, offsetof(fr_stats_t, total_responses) },
-       { 143, offsetof(fr_stats_t, total_dup_requests) },
-       { 144, offsetof(fr_stats_t, total_malformed_requests) },
-       { 145, offsetof(fr_stats_t, total_bad_authenticators) },
-       { 146, offsetof(fr_stats_t, total_packets_dropped) },
-       { 147, offsetof(fr_stats_t, total_unknown_types) },
+       { PW_FREERADIUS_TOTAL_PROXY_ACCESS_REQUESTS, offsetof(fr_stats_t, total_requests) },
+       { PW_FREERADIUS_TOTAL_PROXY_ACCESS_ACCEPTS, offsetof(fr_stats_t, total_access_accepts) },
+       { PW_FREERADIUS_TOTAL_PROXY_ACCESS_REJECTS, offsetof(fr_stats_t, total_access_rejects) },
+       { PW_FREERADIUS_TOTAL_PROXY_ACCESS_CHALLENGES, offsetof(fr_stats_t, total_access_challenges) },
+       { PW_FREERADIUS_TOTAL_PROXY_AUTH_RESPONSES, offsetof(fr_stats_t, total_responses) },
+       { PW_FREERADIUS_TOTAL_PROXY_AUTH_DUPLICATE_REQUESTS, offsetof(fr_stats_t, total_dup_requests) },
+       { PW_FREERADIUS_TOTAL_PROXY_AUTH_MALFORMED_REQUESTS, offsetof(fr_stats_t, total_malformed_requests) },
+       { PW_FREERADIUS_TOTAL_PROXY_AUTH_INVALID_REQUESTS, offsetof(fr_stats_t, total_bad_authenticators) },
+       { PW_FREERADIUS_TOTAL_PROXY_AUTH_DROPPED_REQUESTS, offsetof(fr_stats_t, total_packets_dropped) },
+       { PW_FREERADIUS_TOTAL_PROXY_AUTH_UNKNOWN_TYPES, offsetof(fr_stats_t, total_unknown_types) },
        { 0, 0 }
 };
 #endif
@@ -411,53 +409,53 @@ static fr_stats2vp proxy_authvp[] = {
  *     Accounting
  */
 static fr_stats2vp acctvp[] = {
-       { 148, offsetof(fr_stats_t, total_requests) },
-       { 149, offsetof(fr_stats_t, total_responses) },
-       { 150, offsetof(fr_stats_t, total_dup_requests) },
-       { 151, offsetof(fr_stats_t, total_malformed_requests) },
-       { 152, offsetof(fr_stats_t, total_bad_authenticators) },
-       { 153, offsetof(fr_stats_t, total_packets_dropped) },
-       { 154, offsetof(fr_stats_t, total_unknown_types) },
+       { PW_FREERADIUS_TOTAL_ACCOUNTING_REQUESTS, offsetof(fr_stats_t, total_requests) },
+       { PW_FREERADIUS_TOTAL_ACCOUNTING_RESPONSES, offsetof(fr_stats_t, total_responses) },
+       { PW_FREERADIUS_TOTAL_ACCT_DUPLICATE_REQUESTS, offsetof(fr_stats_t, total_dup_requests) },
+       { PW_FREERADIUS_TOTAL_ACCT_MALFORMED_REQUESTS, offsetof(fr_stats_t, total_malformed_requests) },
+       { PW_FREERADIUS_TOTAL_ACCT_INVALID_REQUESTS, offsetof(fr_stats_t, total_bad_authenticators) },
+       { PW_FREERADIUS_TOTAL_ACCT_DROPPED_REQUESTS, offsetof(fr_stats_t, total_packets_dropped) },
+       { PW_FREERADIUS_TOTAL_ACCT_UNKNOWN_TYPES, offsetof(fr_stats_t, total_unknown_types) },
        { 0, 0 }
 };
 
 #ifdef WITH_PROXY
 static fr_stats2vp proxy_acctvp[] = {
-       { 155, offsetof(fr_stats_t, total_requests) },
-       { 156, offsetof(fr_stats_t, total_responses) },
-       { 157, offsetof(fr_stats_t, total_dup_requests) },
-       { 158, offsetof(fr_stats_t, total_malformed_requests) },
-       { 159, offsetof(fr_stats_t, total_bad_authenticators) },
-       { 160, offsetof(fr_stats_t, total_packets_dropped) },
-       { 161, offsetof(fr_stats_t, total_unknown_types) },
+       { PW_FREERADIUS_TOTAL_PROXY_ACCOUNTING_REQUESTS, offsetof(fr_stats_t, total_requests) },
+       { PW_FREERADIUS_TOTAL_PROXY_ACCOUNTING_RESPONSES, offsetof(fr_stats_t, total_responses) },
+       { PW_FREERADIUS_TOTAL_PROXY_ACCT_DUPLICATE_REQUESTS, offsetof(fr_stats_t, total_dup_requests) },
+       { PW_FREERADIUS_TOTAL_PROXY_ACCT_MALFORMED_REQUESTS, offsetof(fr_stats_t, total_malformed_requests) },
+       { PW_FREERADIUS_TOTAL_PROXY_ACCT_INVALID_REQUESTS, offsetof(fr_stats_t, total_bad_authenticators) },
+       { PW_FREERADIUS_TOTAL_PROXY_ACCT_DROPPED_REQUESTS, offsetof(fr_stats_t, total_packets_dropped) },
+       { PW_FREERADIUS_TOTAL_PROXY_ACCT_UNKNOWN_TYPES, offsetof(fr_stats_t, total_unknown_types) },
        { 0, 0 }
 };
 #endif
 #endif
 
 static fr_stats2vp client_authvp[] = {
-       { 128, offsetof(fr_stats_t, total_requests) },
-       { 129, offsetof(fr_stats_t, total_access_accepts) },
-       { 130, offsetof(fr_stats_t, total_access_rejects) },
-       { 131, offsetof(fr_stats_t, total_access_challenges) },
-       { 132, offsetof(fr_stats_t, total_responses) },
-       { 133, offsetof(fr_stats_t, total_dup_requests) },
-       { 134, offsetof(fr_stats_t, total_malformed_requests) },
-       { 135, offsetof(fr_stats_t, total_bad_authenticators) },
-       { 136, offsetof(fr_stats_t, total_packets_dropped) },
-       { 137, offsetof(fr_stats_t, total_unknown_types) },
+       { PW_FREERADIUS_TOTAL_ACCESS_REQUESTS, offsetof(fr_stats_t, total_requests) },
+       { PW_FREERADIUS_TOTAL_ACCESS_ACCEPTS, offsetof(fr_stats_t, total_access_accepts) },
+       { PW_FREERADIUS_TOTAL_ACCESS_REJECTS, offsetof(fr_stats_t, total_access_rejects) },
+       { PW_FREERADIUS_TOTAL_ACCESS_CHALLENGES, offsetof(fr_stats_t, total_access_challenges) },
+       { PW_FREERADIUS_TOTAL_AUTH_RESPONSES, offsetof(fr_stats_t, total_responses) },
+       { PW_FREERADIUS_TOTAL_AUTH_DUPLICATE_REQUESTS, offsetof(fr_stats_t, total_dup_requests) },
+       { PW_FREERADIUS_TOTAL_AUTH_MALFORMED_REQUESTS, offsetof(fr_stats_t, total_malformed_requests) },
+       { PW_FREERADIUS_TOTAL_AUTH_INVALID_REQUESTS, offsetof(fr_stats_t, total_bad_authenticators) },
+       { PW_FREERADIUS_TOTAL_AUTH_DROPPED_REQUESTS, offsetof(fr_stats_t, total_packets_dropped) },
+       { PW_FREERADIUS_TOTAL_AUTH_UNKNOWN_TYPES, offsetof(fr_stats_t, total_unknown_types) },
        { 0, 0 }
 };
 
 #ifdef WITH_ACCOUNTING
 static fr_stats2vp client_acctvp[] = {
-       { 148, offsetof(fr_stats_t, total_requests) },
-       { 149, offsetof(fr_stats_t, total_responses) },
-       { 150, offsetof(fr_stats_t, total_dup_requests) },
-       { 151, offsetof(fr_stats_t, total_malformed_requests) },
-       { 152, offsetof(fr_stats_t, total_bad_authenticators) },
-       { 153, offsetof(fr_stats_t, total_packets_dropped) },
-       { 154, offsetof(fr_stats_t, total_unknown_types) },
+       { PW_FREERADIUS_TOTAL_ACCOUNTING_REQUESTS, offsetof(fr_stats_t, total_requests) },
+       { PW_FREERADIUS_TOTAL_ACCOUNTING_RESPONSES, offsetof(fr_stats_t, total_responses) },
+       { PW_FREERADIUS_TOTAL_ACCT_DUPLICATE_REQUESTS, offsetof(fr_stats_t, total_dup_requests) },
+       { PW_FREERADIUS_TOTAL_ACCT_MALFORMED_REQUESTS, offsetof(fr_stats_t, total_malformed_requests) },
+       { PW_FREERADIUS_TOTAL_ACCT_INVALID_REQUESTS, offsetof(fr_stats_t, total_bad_authenticators) },
+       { PW_FREERADIUS_TOTAL_ACCT_DROPPED_REQUESTS, offsetof(fr_stats_t, total_packets_dropped) },
+       { PW_FREERADIUS_TOTAL_ACCT_UNKNOWN_TYPES, offsetof(fr_stats_t, total_unknown_types) },
        { 0, 0 }
 };
 #endif
@@ -490,7 +488,7 @@ void request_stats_reply(REQUEST *request)
        rad_assert(request->packet->code == PW_CODE_STATUS_SERVER);
        rad_assert(request->listener->type == RAD_LISTEN_NONE);
 
-       flag = fr_pair_find_by_num(request->packet->vps, 127, VENDORPEC_FREERADIUS, TAG_ANY);
+       flag = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATISTICS_TYPE, VENDORPEC_FREERADIUS, TAG_ANY);
        if (!flag || (flag->vp_integer == 0)) return;
 
        /*
@@ -536,10 +534,10 @@ void request_stats_reply(REQUEST *request)
         */
        if ((flag->vp_integer & 0x10) != 0) {
                vp = radius_pair_create(request->reply, &request->reply->vps,
-                                      176, VENDORPEC_FREERADIUS);
+                                      PW_FREERADIUS_STATS_START_TIME, VENDORPEC_FREERADIUS);
                if (vp) vp->vp_date = start_time.tv_sec;
                vp = radius_pair_create(request->reply, &request->reply->vps,
-                                      177, VENDORPEC_FREERADIUS);
+                                      PW_FREERADIUS_STATS_HUP_TIME, VENDORPEC_FREERADIUS);
                if (vp) vp->vp_date = hup_time.tv_sec;
 
 #ifdef HAVE_PTHREAD_H
@@ -549,7 +547,7 @@ void request_stats_reply(REQUEST *request)
 
                for (i = 0; i <= 4; i++) {
                        vp = radius_pair_create(request->reply, &request->reply->vps,
-                                              162 + i, VENDORPEC_FREERADIUS);
+                                              PW_FREERADIUS_QUEUE_LEN_INTERNAL + i, VENDORPEC_FREERADIUS);
 
                        if (!vp) continue;
                        vp->vp_integer = array[i];
@@ -557,7 +555,7 @@ void request_stats_reply(REQUEST *request)
 
                for (i = 0; i < 2; i++) {
                        vp = radius_pair_create(request->reply, &request->reply->vps,
-                                              181 + i, VENDORPEC_FREERADIUS);
+                                              PW_FREERADIUS_QUEUE_PPS_IN + i, VENDORPEC_FREERADIUS);
 
                        if (!vp) continue;
                        vp->vp_integer = pps[i];
@@ -578,9 +576,9 @@ void request_stats_reply(REQUEST *request)
                 *      See if we need to look up the client by server
                 *      socket.
                 */
-               server_ip = fr_pair_find_by_num(request->packet->vps, 170, VENDORPEC_FREERADIUS, TAG_ANY);
+               server_ip = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_IP_ADDRESS, VENDORPEC_FREERADIUS, TAG_ANY);
                if (server_ip) {
-                       server_port = fr_pair_find_by_num(request->packet->vps, 171, VENDORPEC_FREERADIUS, TAG_ANY);
+                       server_port = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_PORT, VENDORPEC_FREERADIUS, TAG_ANY);
 
                        if (server_port) {
                                ipaddr.af = AF_INET;
@@ -595,7 +593,7 @@ void request_stats_reply(REQUEST *request)
                }
 
 
-               vp = fr_pair_find_by_num(request->packet->vps, 167, VENDORPEC_FREERADIUS, TAG_ANY);
+               vp = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_CLIENT_IP_ADDRESS, VENDORPEC_FREERADIUS, TAG_ANY);
                if (vp) {
                        memset(&ipaddr, 0, sizeof(ipaddr));
                        ipaddr.af = AF_INET;
@@ -610,7 +608,7 @@ void request_stats_reply(REQUEST *request)
                        /*
                         *      Else look it up by number.
                         */
-               } else if ((vp = fr_pair_find_by_num(request->packet->vps, 168, VENDORPEC_FREERADIUS, TAG_ANY)) != NULL) {
+               } else if ((vp = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_CLIENT_NUMBER, VENDORPEC_FREERADIUS, TAG_ANY)) != NULL) {
                        client = client_findbynumber(cl, vp->vp_integer);
                }
 
@@ -629,7 +627,7 @@ void request_stats_reply(REQUEST *request)
                            (client->ipaddr.af == AF_INET)) {
                                vp = radius_pair_create(request->reply,
                                                       &request->reply->vps,
-                                                      167, VENDORPEC_FREERADIUS);
+                                                      PW_FREERADIUS_STATS_CLIENT_IP_ADDRESS, VENDORPEC_FREERADIUS);
                                if (vp) {
                                        vp->vp_ipaddr = client->ipaddr.ipaddr.ip4addr.s_addr;
                                }
@@ -637,7 +635,7 @@ void request_stats_reply(REQUEST *request)
                                if (client->ipaddr.prefix != 32) {
                                        vp = radius_pair_create(request->reply,
                                                               &request->reply->vps,
-                                                              169, VENDORPEC_FREERADIUS);
+                                                              PW_FREERADIUS_STATS_CLIENT_NETMASK, VENDORPEC_FREERADIUS);
                                        if (vp) {
                                                vp->vp_integer = client->ipaddr.prefix;
                                        }
@@ -658,7 +656,7 @@ void request_stats_reply(REQUEST *request)
                                                    &client->auth);
                        }
 #ifdef WITH_ACCOUNTING
-                       if ((flag->vp_integer & 0x01) != 0) {
+                       if ((flag->vp_integer & 0x02) != 0) {
                                request_stats_addvp(request, client_acctvp,
                                                    &client->acct);
                        }
@@ -679,10 +677,10 @@ void request_stats_reply(REQUEST *request)
                 *      See if we need to look up the server by socket
                 *      socket.
                 */
-               server_ip = fr_pair_find_by_num(request->packet->vps, 170, VENDORPEC_FREERADIUS, TAG_ANY);
+               server_ip = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_IP_ADDRESS, VENDORPEC_FREERADIUS, TAG_ANY);
                if (!server_ip) return;
 
-               server_port = fr_pair_find_by_num(request->packet->vps, 171, VENDORPEC_FREERADIUS, TAG_ANY);
+               server_port = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_PORT, VENDORPEC_FREERADIUS, TAG_ANY);
                if (!server_port) return;
 
                ipaddr.af = AF_INET;
@@ -730,10 +728,10 @@ void request_stats_reply(REQUEST *request)
                 *      See if we need to look up the server by socket
                 *      socket.
                 */
-               server_ip = fr_pair_find_by_num(request->packet->vps, 170, VENDORPEC_FREERADIUS, TAG_ANY);
+               server_ip = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_IP_ADDRESS, VENDORPEC_FREERADIUS, TAG_ANY);
                if (!server_ip) return;
 
-               server_port = fr_pair_find_by_num(request->packet->vps, 171, VENDORPEC_FREERADIUS, TAG_ANY);
+               server_port = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_PORT, VENDORPEC_FREERADIUS, TAG_ANY);
                if (!server_port) return;
 
 #ifndef NDEBUG
@@ -755,17 +753,17 @@ void request_stats_reply(REQUEST *request)
                        fr_pair_copy(request->reply, server_port));
 
                vp = radius_pair_create(request->reply, &request->reply->vps,
-                                      172, VENDORPEC_FREERADIUS);
+                                      PW_FREERADIUS_STATS_SERVER_OUTSTANDING_REQUESTS, VENDORPEC_FREERADIUS);
                if (vp) vp->vp_integer = home->currently_outstanding;
 
                vp = radius_pair_create(request->reply, &request->reply->vps,
-                                      173, VENDORPEC_FREERADIUS);
+                                      PW_FREERADIUS_STATS_SERVER_STATE, VENDORPEC_FREERADIUS);
                if (vp) vp->vp_integer = home->state;
 
                if ((home->state == HOME_STATE_ALIVE) &&
                    (home->revive_time.tv_sec != 0)) {
                        vp = radius_pair_create(request->reply, &request->reply->vps,
-                                              175, VENDORPEC_FREERADIUS);
+                                              PW_FREERADIUS_STATS_SERVER_TIME_OF_LIFE, VENDORPEC_FREERADIUS);
                        if (vp) vp->vp_date = home->revive_time.tv_sec;
                }
 
@@ -773,22 +771,22 @@ void request_stats_reply(REQUEST *request)
                    (home->ema.window > 0)) {
                                vp = radius_pair_create(request->reply,
                                                       &request->reply->vps,
-                                                      178, VENDORPEC_FREERADIUS);
+                                                      PW_FREERADIUS_SERVER_EMA_WINDOW, VENDORPEC_FREERADIUS);
                                if (vp) vp->vp_integer = home->ema.window;
                                vp = radius_pair_create(request->reply,
                                                       &request->reply->vps,
-                                                      179, VENDORPEC_FREERADIUS);
+                                                      PW_FREERADIUS_SERVER_EMA_USEC_WINDOW_1, VENDORPEC_FREERADIUS);
                                if (vp) vp->vp_integer = home->ema.ema1 / EMA_SCALE;
                                vp = radius_pair_create(request->reply,
                                                       &request->reply->vps,
-                                                      180, VENDORPEC_FREERADIUS);
+                                                      PW_FREERADIUS_SERVER_EMA_USEC_WINDOW_10, VENDORPEC_FREERADIUS);
                                if (vp) vp->vp_integer = home->ema.ema10 / EMA_SCALE;
 
                }
 
                if (home->state == HOME_STATE_IS_DEAD) {
                        vp = radius_pair_create(request->reply, &request->reply->vps,
-                                              174, VENDORPEC_FREERADIUS);
+                                              PW_FREERADIUS_STATS_SERVER_TIME_OF_DEATH, VENDORPEC_FREERADIUS);
                        if (vp) vp->vp_date = home->zombie_period_start.tv_sec + home->zombie_period;
                }
 
@@ -798,11 +796,11 @@ void request_stats_reply(REQUEST *request)
                 *      FIXME: do this for clients, too!
                 */
                vp = radius_pair_create(request->reply, &request->reply->vps,
-                                      184, VENDORPEC_FREERADIUS);
+                                      PW_FREERADIUS_STATS_LAST_PACKET_RECV, VENDORPEC_FREERADIUS);
                if (vp) vp->vp_date = home->last_packet_recv;
 
                vp = radius_pair_create(request->reply, &request->reply->vps,
-                                      185, VENDORPEC_FREERADIUS);
+                                      PW_FREERADIUS_STATS_LAST_PACKET_SENT, VENDORPEC_FREERADIUS);
                if (vp) vp->vp_date = home->last_packet_sent;
 
                if (((flag->vp_integer & 0x01) != 0) &&
index af91077..58bc908 100644 (file)
@@ -551,7 +551,7 @@ static int request_dequeue(REQUEST **prequest)
        rad_assert(request->magic == REQUEST_MAGIC);
 
        request->component = "<core>";
-       request->module = "<running>";
+       request->module = "";
        request->child_state = REQUEST_RUNNING;
 
        /*
index d86391f..bec1af6 100644 (file)
@@ -68,16 +68,51 @@ typedef struct libssl_defect {
        char const      *comment;
 } libssl_defect_t;
 
-/* Record critical defects in libssl here (newest first)*/
+/* Record critical defects in libssl here, new versions of OpenSSL to older versions of OpenSSL.  */
 static libssl_defect_t libssl_defects[] =
 {
        {
+               .low            = 0x01010101f,          /* 1.1.0a */
+               .high           = 0x01010101f,          /* 1.1.0a */
+               .id             = "CVE-2016-6309",
+               .name           = "OCSP status request extension",
+               .comment        = "For more information see https://www.openssl.org/news/secadv/20160926.txt"
+       },
+       {
+               .low            = 0x01010100f,          /* 1.1.0  */
+               .high           = 0x01010100f,          /* 1.1.0  */
+               .id             = "CVE-2016-6304",
+               .name           = "OCSP status request extension",
+               .comment        = "For more information see https://www.openssl.org/news/secadv/20160922.txt"
+       },
+       {
+               .low            = 0x01000209f,          /* 1.0.2i */
+               .high           = 0x01000209f,          /* 1.0.2i */
+               .id             = "CVE-2016-7052",
+               .name           = "OCSP status request extension",
+               .comment        = "For more information see https://www.openssl.org/news/secadv/20160926.txt"
+       },
+       {
+               .low            = 0x01000200f,          /* 1.0.2  */
+               .high           = 0x01000208f,          /* 1.0.2h */
+               .id             = "CVE-2016-6304",
+               .name           = "OCSP status request extension",
+               .comment        = "For more information see https://www.openssl.org/news/secadv/20160922.txt"
+       },
+       {
+               .low            = 0x01000100f,          /* 1.0.1  */
+               .high           = 0x01000114f,          /* 1.0.1t */
+               .id             = "CVE-2016-6304",
+               .name           = "OCSP status request extension",
+               .comment        = "For more information see https://www.openssl.org/news/secadv/20160922.txt"
+       },
+       {
                .low            = 0x010001000,          /* 1.0.1  */
                .high           = 0x01000106f,          /* 1.0.1f */
                .id             = "CVE-2014-0160",
                .name           = "Heartbleed",
                .comment        = "For more information see http://heartbleed.com"
-       }
+       },
 };
 #endif /* ENABLE_OPENSSL_VERSION_CHECK */
 
@@ -118,6 +153,183 @@ static unsigned int       record_plus(record_t *buf, void const *ptr,
 static unsigned int    record_minus(record_t *buf, void *ptr,
                                     unsigned int size);
 
+DIAG_OFF(format-nonliteral)
+/** Print errors in the TLS thread local error stack
+ *
+ * Drains the thread local OpenSSL error queue, and prints out errors.
+ *
+ * @param[in] request  The current request (may be NULL).
+ * @param[in] msg      Error message describing the operation being attempted.
+ * @param[in] ap       Arguments for msg.
+ * @return the number of errors drained from the stack.
+ */
+static int tls_verror_log(REQUEST *request, char const *msg, va_list ap)
+{
+       unsigned long   error;
+       char            *p;
+       int             in_stack = 0;
+       char            buffer[256];
+
+       int             line;
+       char const      *file;
+
+       /*
+        *      Pop the first error, so ERR_peek_error()
+        *      can be used to determine if there are
+        *      multiple errors.
+        */
+       error = ERR_get_error_line(&file, &line);
+
+       if (msg) {
+               p = talloc_vasprintf(request, msg, ap);
+
+               /*
+                *      Single line mode (there's only one error)
+                */
+               if (error && !ERR_peek_error()) {
+                       ERR_error_string_n(error, buffer, sizeof(buffer));
+
+                       /* Extra verbose */
+                       if ((request && RDEBUG_ENABLED3) || DEBUG_ENABLED3) {
+                               ROPTIONAL(REDEBUG, ERROR, "%s: %s[%i]:%s", p, file, line, buffer);
+                       } else {
+                               ROPTIONAL(REDEBUG, ERROR, "%s: %s", p, buffer);
+                       }
+
+                       talloc_free(p);
+
+                       return 1;
+               }
+
+               /*
+                *      Print the error we were given, irrespective
+                *      of whether there were any OpenSSL errors.
+                */
+               ROPTIONAL(RERROR, ERROR, "%s", p);
+               talloc_free(p);
+       }
+
+       /*
+        *      Stack mode (there are multiple errors)
+        */
+       if (!error) return 0;
+       do {
+               ERR_error_string_n(error, buffer, sizeof(buffer));
+               /* Extra verbose */
+               if ((request && RDEBUG_ENABLED3) || DEBUG_ENABLED3) {
+                       ROPTIONAL(REDEBUG, ERROR, "%s[%i]:%s", file, line, buffer);
+               } else {
+                       ROPTIONAL(REDEBUG, ERROR, "%s", buffer);
+               }
+               in_stack++;
+       } while ((error = ERR_get_error_line(&file, &line)));
+
+       return in_stack;
+}
+DIAG_ON(format-nonliteral)
+
+/** Print errors in the TLS thread local error stack
+ *
+ * Drains the thread local OpenSSL error queue, and prints out errors.
+ *
+ * @param[in] request  The current request (may be NULL).
+ * @param[in] msg      Error message describing the operation being attempted.
+ * @param[in] ...      Arguments for msg.
+ * @return the number of errors drained from the stack.
+ */
+int tls_error_log(REQUEST *request, char const *msg, ...)
+{
+       va_list ap;
+       int ret;
+
+       va_start(ap, msg);
+       ret = tls_verror_log(request, msg, ap);
+       va_end(ap);
+
+       return ret;
+}
+
+/** Print errors raised by OpenSSL I/O functions
+ *
+ * Drains the thread local OpenSSL error queue, and prints out errors
+ * based on the SSL handle and the return code of the I/O  function.
+ *
+ * OpenSSL lists I/O functions to be:
+ *   - SSL_connect
+ *   - SSL_accept
+ *   - SSL_do_handshake
+ *   - SSL_read
+ *   - SSL_peek
+ *   - SSL_write
+ *
+ * @param request      The current request (may be NULL).
+ * @param session      The current tls_session.
+ * @param ret          from the I/O operation.
+ * @param msg          Error message describing the operation being attempted.
+ * @param ...          Arguments for msg.
+ * @return
+ *     - 0 TLS session cannot continue.
+ *     - 1 TLS session may still be viable.
+ */
+int tls_error_io_log(REQUEST *request, tls_session_t *session, int ret, char const *msg, ...)
+{
+       int     error;
+       va_list ap;
+
+       if (ERR_peek_error()) {
+               va_start(ap, msg);
+               tls_verror_log(request, msg, ap);
+               va_end(ap);
+       }
+
+       error = SSL_get_error(session->ssl, ret);
+       switch (error) {
+       /*
+        *      These seem to be harmless and already "dealt
+        *      with" by our non-blocking environment. NB:
+        *      "ZERO_RETURN" is the clean "error"
+        *      indicating a successfully closed SSL
+        *      tunnel. We let this happen because our IO
+        *      loop should not appear to have broken on
+        *      this condition - and outside the IO loop, the
+        *      "shutdown" state is checked.
+        *
+        *      Don't print anything if we ignore the error.
+        */
+       case SSL_ERROR_NONE:
+       case SSL_ERROR_WANT_READ:
+       case SSL_ERROR_WANT_WRITE:
+       case SSL_ERROR_WANT_X509_LOOKUP:
+       case SSL_ERROR_ZERO_RETURN:
+               break;
+
+       /*
+        *      These seem to be indications of a genuine
+        *      error that should result in the SSL tunnel
+        *      being regarded as "dead".
+        */
+       case SSL_ERROR_SYSCALL:
+               ROPTIONAL(REDEBUG, ERROR, "System call (I/O) error (%i)", ret);
+               return 0;
+
+       case SSL_ERROR_SSL:
+               ROPTIONAL(REDEBUG, ERROR, "TLS protocol error (%i)", ret);
+               return 0;
+
+       /*
+        *      For any other errors that (a) exist, and (b)
+        *      crop up - we need to interpret what to do with
+        *      them - so "politely inform" the caller that
+        *      the code needs updating here.
+        */
+       default:
+               ROPTIONAL(REDEBUG, ERROR, "TLS session error %i (%i)", error, ret);
+               return 0;
+       }
+
+       return 1;
+}
+
 #ifdef PSK_MAX_IDENTITY_LEN
 static bool identity_is_safe(const char *identity)
 {
@@ -137,7 +349,6 @@ static bool identity_is_safe(const char *identity)
        return true;
 }
 
-
 /*
  *     When a client uses TLS-PSK to talk to a server, this callback
  *     is used by the server to determine the PSK to use.
@@ -240,6 +451,32 @@ static unsigned int psk_client_callback(SSL *ssl, UNUSED char const *hint,
 
 #endif
 
+#define MAX_SESSION_SIZE (256)
+
+
+void tls_session_id(SSL_SESSION *ssn, char *buffer, size_t bufsize)
+{
+#if OPENSSL_VERSION_NUMBER < 0x10001000L
+       size_t size;
+
+       size = ssn->session_id_length;
+       if (size > bufsize) size = bufsize;
+
+       fr_bin2hex(buffer, ssn->session_id, size);
+#else
+       unsigned int size;
+       uint8_t const *p;
+
+       p = SSL_SESSION_get_id(ssn, &size);
+       if (size > bufsize) size = bufsize;
+
+       fr_bin2hex(buffer, p, size);
+
+#endif
+}
+
+
+
 static int _tls_session_free(tls_session_t *ssn)
 {
        /*
@@ -257,6 +494,7 @@ static int _tls_session_free(tls_session_t *ssn)
 
 tls_session_t *tls_new_client_session(TALLOC_CTX *ctx, fr_tls_server_conf_t *conf, int fd)
 {
+       int ret;
        int verify_mode;
        tls_session_t *ssn = NULL;
        REQUEST *request;
@@ -298,11 +536,9 @@ tls_session_t *tls_new_client_session(TALLOC_CTX *ctx, fr_tls_server_conf_t *con
        SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_CONF, (void *)conf);
        SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_SSN, (void *)ssn);
        SSL_set_fd(ssn->ssl, fd);
-       if (SSL_connect(ssn->ssl) <= 0) {
-               int err;
-               while ((err = ERR_get_error())) {
-                       ERROR("tls: %s", ERR_error_string(err, NULL));
-               }
+       ret = SSL_connect(ssn->ssl);
+       if (ret <= 0) {
+               tls_error_io_log(NULL, ssn, ret, "Failed in " STRINGIFY(__FUNCTION__) " (SSL_connect)");
                talloc_free(ssn);
 
                return NULL;
@@ -350,8 +586,9 @@ tls_session_t *tls_new_session(TALLOC_CTX *ctx, fr_tls_server_conf_t *conf, REQU
                conf->session_last_flushed = request->timestamp;
        }
 
-       if ((new_tls = SSL_new(conf->ctx)) == NULL) {
-               RERROR("Error creating new SSL session: %s", ERR_error_string(ERR_get_error(), NULL));
+       new_tls = SSL_new(conf->ctx);
+       if (new_tls == NULL) {
+               tls_error_log(request, "Error creating new TLS session");
                return NULL;
        }
 
@@ -442,68 +679,6 @@ tls_session_t *tls_new_session(TALLOC_CTX *ctx, fr_tls_server_conf_t *conf, REQU
 }
 
 /*
- *     Print out some text describing the error.
- */
-static int int_ssl_check(REQUEST *request, SSL *s, int ret, char const *text)
-{
-       int e;
-       unsigned long l;
-
-       if ((l = ERR_get_error()) != 0) {
-               char const *p = ERR_error_string(l, NULL);
-
-               if (p) ROPTIONAL(REDEBUG, ERROR, "SSL says: %s", p);
-       }
-
-       e = SSL_get_error(s, ret);
-       switch (e) {
-       /*
-        *      These seem to be harmless and already "dealt
-        *      with" by our non-blocking environment. NB:
-        *      "ZERO_RETURN" is the clean "error"
-        *      indicating a successfully closed SSL
-        *      tunnel. We let this happen because our IO
-        *      loop should not appear to have broken on
-        *      this condition - and outside the IO loop, the
-        *      "shutdown" state is checked.
-        *
-        *      Don't print anything if we ignore the error.
-        */
-       case SSL_ERROR_NONE:
-       case SSL_ERROR_WANT_READ:
-       case SSL_ERROR_WANT_WRITE:
-       case SSL_ERROR_WANT_X509_LOOKUP:
-       case SSL_ERROR_ZERO_RETURN:
-               break;
-
-       /*
-        *      These seem to be indications of a genuine
-        *      error that should result in the SSL tunnel
-        *      being regarded as "dead".
-        */
-       case SSL_ERROR_SYSCALL:
-               ROPTIONAL(REDEBUG, ERROR, "%s failed in a system call (%d), TLS session failed", text, ret);
-               return 0;
-
-       case SSL_ERROR_SSL:
-               ROPTIONAL(REDEBUG, ERROR, "%s failed inside of TLS (%d), TLS session failed", text, ret);
-               return 0;
-
-       /*
-        *      For any other errors that (a) exist, and (b)
-        *      crop up - we need to interpret what to do with
-        *      them - so "politely inform" the caller that
-        *      the code needs updating here.
-        */
-       default:
-               ROPTIONAL(REDEBUG, ERROR, "FATAL SSL error: %d", e);
-               return 0;
-       }
-
-       return 1;
-}
-
-/*
  * We are the server, we always get the dirty data
  * (Handshake data is also considered as dirty data)
  * During handshake, since SSL API handles itself,
@@ -537,7 +712,7 @@ int tls_handshake_recv(REQUEST *request, tls_session_t *ssn)
                return 1;
        }
 
-       if (!int_ssl_check(request, ssn->ssl, err, "SSL_read")) return 0;
+       if (!tls_error_io_log(request, ssn, err, "Failed in " STRINGIFY(__FUNCTION__) " (SSL_read)")) return 0;
 
        /* Some Extra STATE information for easy debugging */
        if (SSL_is_init_finished(ssn->ssl)) RDEBUG2("SSL Connection Established");
@@ -546,6 +721,19 @@ int tls_handshake_recv(REQUEST *request, tls_session_t *ssn)
        if (SSL_in_accept_init(ssn->ssl)) RDEBUG2("In SSL Accept mode");
        if (SSL_in_connect_init(ssn->ssl)) RDEBUG2("In SSL Connect mode");
 
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+       /*
+        *      Cache the SSL_SESSION pointer.
+        */
+       if (!ssn->ssl_session && SSL_is_init_finished(ssn->ssl)) {
+               ssn->ssl_session = SSL_get_session(ssn->ssl);
+               if (!ssn->ssl_session) {
+                       RDEBUG("Failed getting SSL session");
+                       return 0;
+               }
+       }
+#endif
+
        err = BIO_ctrl_pending(ssn->from_ssl);
        if (err > 0) {
                err = BIO_read(ssn->from_ssl, ssn->dirty_out.data,
@@ -559,7 +747,7 @@ int tls_handshake_recv(REQUEST *request, tls_session_t *ssn)
                        return 1;
 
                } else {
-                       int_ssl_check(request, ssn->ssl, err, "BIO_read");
+                       tls_error_log(NULL, NULL);
                        record_init(&ssn->dirty_in);
                        return 0;
                }
@@ -603,7 +791,10 @@ int tls_handshake_send(REQUEST *request, tls_session_t *ssn)
                if (err > 0) {
                        ssn->dirty_out.used = err;
                } else {
-                       int_ssl_check(request, ssn->ssl, err, "handshake_send");
+                       if (!tls_error_io_log(request, ssn, err,
+                                             "Failed in " STRINGIFY(__FUNCTION__) " (SSL_write)")) {
+                               return 0;
+                       }
                }
        }
 
@@ -694,8 +885,8 @@ static unsigned int record_minus(record_t *rec, void *ptr,
        /*
         *      This is pretty bad...
         */
-       if(rec->used > 0)
-               memmove(rec->data, rec->data + taken, rec->used);
+       if (rec->used > 0) memmove(rec->data, rec->data + taken, rec->used);
+
        return taken;
 }
 
@@ -710,11 +901,9 @@ void tls_session_information(tls_session_t *tls_session)
         *      Don't print this out in the normal course of
         *      operations.
         */
-       if (rad_debug_lvl == 0) {
-               return;
-       }
+       if (rad_debug_lvl == 0) return;
 
-       str_write_p = tls_session->info.origin ? ">>>" : "<<<";
+       str_write_p = tls_session->info.origin ? ">>> send" : "<<< recv";
 
        switch (tls_session->info.version) {
        case SSL2_VERSION:
@@ -938,11 +1127,7 @@ void tls_session_information(tls_session_t *tls_session)
                 str_details1, str_details2);
 
        request = SSL_get_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST);
-       if (request) {
-               RDEBUG2("%s", tls_session->info.info_description);
-       } else {
-               DEBUG2("%s", tls_session->info.info_description);
-       }
+       ROPTIONAL(RDEBUG2, DEBUG2, "%s", tls_session->info.info_description);
 }
 
 static CONF_PARSER cache_config[] = {
@@ -957,6 +1142,7 @@ static CONF_PARSER cache_config[] = {
 };
 
 static CONF_PARSER verify_config[] = {
+       { "skip_if_ocsp_ok", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, verify_skip_if_ocsp_ok), "no" },
        { "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 },
        CONF_PARSER_TERMINATOR
@@ -975,10 +1161,6 @@ static CONF_PARSER ocsp_config[] = {
 #endif
 
 static CONF_PARSER tls_server_config[] = {
-       { "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 },
@@ -993,10 +1175,12 @@ static CONF_PARSER tls_server_config[] = {
        { "psk_hexphrase", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, fr_tls_server_conf_t, psk_password), NULL },
        { "psk_query", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, psk_query), NULL },
 #endif
-       { "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 },
+       { "dh_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, dh_file), NULL },
+       { "random_file", FR_CONF_OFFSET(PW_TYPE_FILE_EXISTS, 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" },
+       { "auto_chain", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, auto_chain), "yes" },
+       { "disable_single_dh_use", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, disable_single_dh_use), NULL },
        { "check_crl", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, check_crl), "no" },
 #ifdef X509_V_FLAG_CRL_CHECK_ALL
        { "check_all_crl", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, check_all_crl), "no" },
@@ -1037,10 +1221,6 @@ static CONF_PARSER tls_server_config[] = {
 
 
 static CONF_PARSER tls_client_config[] = {
-       { "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" },
@@ -1115,18 +1295,12 @@ static int load_dh_params(SSL_CTX *ctx, char *file)
 /*
  *     Print debugging messages, and free data.
  */
-#define MAX_SESSION_SIZE (256)
-
 static void cbtls_remove_session(SSL_CTX *ctx, SSL_SESSION *sess)
 {
-       size_t                  size;
        char                    buffer[2 * MAX_SESSION_SIZE + 1];
        fr_tls_server_conf_t    *conf;
 
-       size = sess->session_id_length;
-       if (size > MAX_SESSION_SIZE) size = MAX_SESSION_SIZE;
-
-       fr_bin2hex(buffer, sess->session_id, size);
+       tls_session_id(sess, buffer, MAX_SESSION_SIZE);
 
        conf = (fr_tls_server_conf_t *)SSL_CTX_get_app_data(ctx);
        if (!conf) {
@@ -1159,7 +1333,6 @@ static void cbtls_remove_session(SSL_CTX *ctx, SSL_SESSION *sess)
 
 static int cbtls_new_session(SSL *ssl, SSL_SESSION *sess)
 {
-       size_t                  size;
        char                    buffer[2 * MAX_SESSION_SIZE + 1];
        fr_tls_server_conf_t    *conf;
        unsigned char           *sess_blob = NULL;
@@ -1172,10 +1345,7 @@ static int cbtls_new_session(SSL *ssl, SSL_SESSION *sess)
                return 0;
        }
 
-       size = sess->session_id_length;
-       if (size > MAX_SESSION_SIZE) size = MAX_SESSION_SIZE;
-
-       fr_bin2hex(buffer, sess->session_id, size);
+       tls_session_id(sess, buffer, MAX_SESSION_SIZE);
 
        {
                int fd, rv, todo, blob_len;
@@ -1275,7 +1445,11 @@ static SSL_SESSION *cbtls_get_session(SSL *ssl, unsigned char *data, int len, in
        {
                int             rv, fd, todo;
                char            filename[256];
-               unsigned char   *p;
+
+               unsigned char const     **o;
+               unsigned char           **p;
+               uint8_t                 *q;
+
                struct stat     st;
                VALUE_PAIR      *vps = NULL;
 
@@ -1311,24 +1485,34 @@ static SSL_SESSION *cbtls_get_session(SSL *ssl, unsigned char *data, int len, in
                        goto err;
                }
 
-               p = sess_data;
+               q = sess_data;
                todo = st.st_size;
                while (todo > 0) {
-                       rv = read(fd, p, todo);
+                       rv = read(fd, q, todo);
                        if (rv < 1) {
                                RWDEBUG("Failed reading persisted session: %s", fr_syserror(errno));
                                close(fd);
                                goto err;
                        }
                        todo -= rv;
-                       p += rv;
+                       q += rv;
                }
                close(fd);
 
-               /* openssl mutates &p */
-               p = sess_data;
-               sess = d2i_SSL_SESSION(NULL, (unsigned char const **)(void **) &p, st.st_size);
-
+               /*
+                *      OpenSSL mutates what's passed in, so we assign sess_data to q,
+                *      so the value of q gets mutated, and not the value of sess_data.
+                *
+                *      We then need a pointer to hold &q, but it can't be const, because
+                *      clang complains about lack of consting in nested pointer types.
+                *
+                *      So we memcpy the value of that pointer, to one that
+                *      does have a const, which we then pass into d2i_SSL_SESSION *sigh*.
+                */
+               q = sess_data;
+               p = &q;
+               memcpy(&o, &p, sizeof(o));
+               sess = d2i_SSL_SESSION(NULL, o, st.st_size);
                if (!sess) {
                        RWDEBUG("Failed loading persisted session: %s", ERR_error_string(ERR_get_error(), NULL));
                        goto err;
@@ -1393,8 +1577,14 @@ static int ocsp_parse_cert_url(X509 *cert, char **host_out, char **port_out,
 /* Maximum leeway in validity period: default 5 minutes */
 #define MAX_VALIDITY_PERIOD     (5 * 60)
 
-static int ocsp_check(REQUEST *request, X509_STORE *store, X509 *issuer_cert, X509 *client_cert,
-                     fr_tls_server_conf_t *conf)
+typedef enum {
+       OCSP_STATUS_FAILED      = 0,
+       OCSP_STATUS_OK          = 1,
+       OCSP_STATUS_SKIPPED     = 2,
+} ocsp_status_t;
+
+static ocsp_status_t ocsp_check(REQUEST *request, X509_STORE *store, X509 *issuer_cert, X509 *client_cert,
+                               fr_tls_server_conf_t *conf)
 {
        OCSP_CERTID     *certid;
        OCSP_REQUEST    *req;
@@ -1407,7 +1597,7 @@ static int ocsp_check(REQUEST *request, X509_STORE *store, X509 *issuer_cert, X5
        int             use_ssl = -1;
        long            nsec = MAX_VALIDITY_PERIOD, maxage = -1;
        BIO             *cbio, *bio_out;
-       int             ocsp_ok = 0;
+       ocsp_status_t   ocsp_status = OCSP_STATUS_FAILED;
        int             status;
        ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
        int             reason;
@@ -1417,6 +1607,7 @@ static int ocsp_check(REQUEST *request, X509_STORE *store, X509 *issuer_cert, X5
        struct timeval  now;
        struct timeval  when;
 #endif
+       VALUE_PAIR      *vp;
 
        /*
         * Create OCSP Request
@@ -1440,8 +1631,7 @@ static int ocsp_check(REQUEST *request, X509_STORE *store, X509 *issuer_cert, X5
                OCSP_parse_url(url, &host, &port, &path, &use_ssl);
                if (!host || !port || !path) {
                        RWDEBUG("ocsp: Host or port or path missing from configured URL \"%s\".  Not doing OCSP", url);
-                       ocsp_ok = 2;
-                       goto ocsp_skip;
+                       goto skipped;
                }
        } else {
                int ret;
@@ -1458,8 +1648,7 @@ static int ocsp_check(REQUEST *request, X509_STORE *store, X509 *issuer_cert, X5
                                goto use_ocsp_url;
                        }
                        RWDEBUG("ocsp: No OCSP URL in certificate.  Not doing OCSP");
-                       ocsp_ok = 2;
-                       goto ocsp_skip;
+                       goto skipped;
 
                case 1:
                        break;
@@ -1471,7 +1660,7 @@ static int ocsp_check(REQUEST *request, X509_STORE *store, X509 *issuer_cert, X5
        /* Check host and port length are sane, then create Host: HTTP header */
        if ((strlen(host) + strlen(port) + 2) > sizeof(hostheader)) {
                RWDEBUG("ocsp: Host and port too long");
-               goto ocsp_skip;
+               goto skipped;
        }
        snprintf(hostheader, sizeof(hostheader), "%s:%s", host, port);
 
@@ -1495,7 +1684,7 @@ static int ocsp_check(REQUEST *request, X509_STORE *store, X509 *issuer_cert, X5
        resp = OCSP_sendreq_bio(cbio, path, req);
        if (!resp) {
                REDEBUG("ocsp: Couldn't get OCSP response");
-               ocsp_ok = 2;
+               ocsp_status = OCSP_STATUS_SKIPPED;
                goto ocsp_end;
        }
 #else
@@ -1505,26 +1694,26 @@ static int ocsp_check(REQUEST *request, X509_STORE *store, X509 *issuer_cert, X5
        rc = BIO_do_connect(cbio);
        if ((rc <= 0) && ((!conf->ocsp_timeout) || !BIO_should_retry(cbio))) {
                REDEBUG("ocsp: Couldn't connect to OCSP responder");
-               ocsp_ok = 2;
+               ocsp_status = OCSP_STATUS_SKIPPED;
                goto ocsp_end;
        }
 
        ctx = OCSP_sendreq_new(cbio, path, NULL, -1);
        if (!ctx) {
                REDEBUG("ocsp: Couldn't create OCSP request");
-               ocsp_ok = 2;
+               ocsp_status = OCSP_STATUS_SKIPPED;
                goto ocsp_end;
        }
 
        if (!OCSP_REQ_CTX_add1_header(ctx, "Host", hostheader)) {
                REDEBUG("ocsp: Couldn't set Host header");
-               ocsp_ok = 2;
+               ocsp_status = OCSP_STATUS_SKIPPED;
                goto ocsp_end;
        }
 
        if (!OCSP_REQ_CTX_set1_req(ctx, req)) {
                REDEBUG("ocsp: Couldn't add data to OCSP request");
-               ocsp_ok = 2;
+               ocsp_status = OCSP_STATUS_SKIPPED;
                goto ocsp_end;
        }
 
@@ -1542,7 +1731,7 @@ static int ocsp_check(REQUEST *request, X509_STORE *store, X509 *issuer_cert, X5
 
        if (conf->ocsp_timeout && (rc == -1) && BIO_should_retry(cbio)) {
                REDEBUG("ocsp: Response timed out");
-               ocsp_ok = 2;
+               ocsp_status = OCSP_STATUS_SKIPPED;
                goto ocsp_end;
        }
 
@@ -1550,7 +1739,7 @@ static int ocsp_check(REQUEST *request, X509_STORE *store, X509 *issuer_cert, X5
 
        if (rc == 0) {
                REDEBUG("ocsp: Couldn't get OCSP response");
-               ocsp_ok = 2;
+               ocsp_status = OCSP_STATUS_SKIPPED;
                goto ocsp_end;
        }
 #endif
@@ -1599,7 +1788,9 @@ static int ocsp_check(REQUEST *request, X509_STORE *store, X509 *issuer_cert, X5
        switch (status) {
        case V_OCSP_CERTSTATUS_GOOD:
                RDEBUG2("ocsp: Cert status: good");
-               ocsp_ok = 1;
+               vp = pair_make_request("TLS-OCSP-Cert-Valid", NULL, T_OP_SET);
+               vp->vp_integer = 1;     /* yes */
+               ocsp_status = OCSP_STATUS_OK;
                break;
 
        default:
@@ -1626,29 +1817,37 @@ ocsp_end:
        if (bio_out) BIO_free(bio_out);
        OCSP_BASICRESP_free(bresp);
 
- ocsp_skip:
-       switch (ocsp_ok) {
-       case 1:
+       switch (ocsp_status) {
+       case OCSP_STATUS_OK:
                RDEBUG2("ocsp: Certificate is valid");
                break;
 
-       case 2:
+       case OCSP_STATUS_SKIPPED:
+       skipped:
+               vp = pair_make_request("TLS-OCSP-Cert-Valid", NULL, T_OP_SET);
+               vp->vp_integer = 2;     /* skipped */
                if (conf->ocsp_softfail) {
                        RWDEBUG("ocsp: Unable to check certificate, assuming it's valid");
                        RWDEBUG("ocsp: This may be insecure");
-                       ocsp_ok = 1;
+
+                       /* Remove OpenSSL errors from queue or handshake will fail */
+                       while (ERR_get_error());
+
+                       ocsp_status = OCSP_STATUS_SKIPPED;
                } else {
                        REDEBUG("ocsp: Unable to check certificate, failing");
-                       ocsp_ok = 0;
+                       ocsp_status = OCSP_STATUS_FAILED;
                }
                break;
 
        default:
+               vp = pair_make_request("TLS-OCSP-Cert-Valid", NULL, T_OP_SET);
+               vp->vp_integer = 0;     /* no */
                REDEBUG("ocsp: Certificate has been expired/revoked");
                break;
        }
 
-       return ocsp_ok;
+       return ocsp_status;
 }
 #endif /* HAVE_OPENSSL_OCSP_H */
 
@@ -1724,6 +1923,7 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
 #ifdef HAVE_OPENSSL_OCSP_H
        X509_STORE      *ocsp_store = NULL;
        X509            *issuer_cert;
+       bool            do_verify = false;
 #endif
        VALUE_PAIR      *vp;
        TALLOC_CTX      *talloc_ctx;
@@ -1756,7 +1956,7 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
 
        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);
+       ocsp_store = conf->ocsp_store;
 #endif
 
        talloc_ctx = SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_TALLOC);
@@ -2028,23 +2228,55 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
                } /* check_cert_cn */
 
 #ifdef HAVE_OPENSSL_OCSP_H
-               if (my_ok && conf->ocsp_enable){
-                       RDEBUG2("Starting OCSP Request");
-                       if (X509_STORE_CTX_get1_issuer(&issuer_cert, ctx, client_cert) != 1) {
-                               RERROR("Couldn't get issuer_cert for %s", common_name);
+               if (my_ok) {
+                       /*
+                        *      No OCSP, allow external verification.
+                        */
+                       if (!conf->ocsp_enable) {
+                               do_verify = true;
+
                        } else {
-                               my_ok = ocsp_check(request, ocsp_store, issuer_cert, client_cert, conf);
+                               RDEBUG2("Starting OCSP Request");
+                               if ((X509_STORE_CTX_get1_issuer(&issuer_cert, ctx, client_cert) != 1) ||
+                                   !issuer_cert) {
+                                       /*
+                                        *      Allow for external verify.
+                                        */
+                                       RERROR("Couldn't get issuer_cert for %s", common_name);
+                                       do_verify = true;
+
+                               } else {
+                                       /*
+                                        *      Do the full OCSP checks.
+                                        *
+                                        *      If they fail, don't run the external verify.  We don't want
+                                        *      to allow admins to force authentication success for bad
+                                        *      certificates.
+                                        *
+                                        *      If the OCSP checks succeed, check whether we still want to
+                                        *      run the external verification routine.  If it's marked as
+                                        *      "skip verify on OK", then we don't do verify.
+                                        */
+                                       my_ok = ocsp_check(request, ocsp_store, issuer_cert, client_cert, conf);
+                                       if (my_ok != OCSP_STATUS_FAILED) {
+                                               do_verify = !conf->verify_skip_if_ocsp_ok;
+                                       }
+                               }
                        }
                }
 #endif
 
-               while (conf->verify_client_cert_cmd) {
+               if ((my_ok != OCSP_STATUS_FAILED)
+#ifdef HAVE_OPENSSL_OCSP_H
+                   && do_verify
+#endif
+                       ) while (conf->verify_client_cert_cmd) {
                        char filename[256];
                        int fd;
                        FILE *fp;
 
                        snprintf(filename, sizeof(filename), "%s/%s.client.XXXXXXXX",
-                                conf->verify_tmp_dir, progname);
+                                conf->verify_tmp_dir, main_config.name);
                        fd = mkstemp(filename);
                        if (fd < 0) {
                                RDEBUG("Failed creating file in %s: %s",
@@ -2088,10 +2320,12 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
                        unlink(filename);
                        break;
                }
-
-
        } /* depth == 0 */
 
+       if (certs && request && !my_ok) {
+               fr_pair_add(&request->packet->vps, fr_pair_list_copy(request->packet, *certs));
+       }
+
        if (RDEBUG_ENABLED3) {
                RDEBUG3("chain-depth   : %d", depth);
                RDEBUG3("error         : %d", err);
@@ -2102,7 +2336,8 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
                RDEBUG3("issuer        : %s", issuer);
                RDEBUG3("verify return : %d", my_ok);
        }
-       return my_ok;
+
+       return (my_ok != 0);
 }
 
 
@@ -2122,9 +2357,8 @@ static X509_STORE *init_revocation_store(fr_tls_server_conf_t *conf)
 
        /* Load the CAs we trust */
        if (conf->ca_file || conf->ca_path)
-               if(!X509_STORE_load_locations(store, conf->ca_file, conf->ca_path)) {
-                       ERROR(LOG_PREFIX ": X509_STORE error %s", ERR_error_string(ERR_get_error(), NULL));
-                       ERROR(LOG_PREFIX ": Error reading Trusted root CA list %s",conf->ca_file );
+               if (!X509_STORE_load_locations(store, conf->ca_file, conf->ca_path)) {
+                       tls_error_log(NULL, "Error reading Trusted root CA list \"%s\"", conf->ca_file);
                        return NULL;
                }
 
@@ -2142,7 +2376,7 @@ static X509_STORE *init_revocation_store(fr_tls_server_conf_t *conf)
 
 #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
 #ifndef OPENSSL_NO_ECDH
-static int set_ecdh_curve(SSL_CTX *ctx, char const *ecdh_curve)
+static int set_ecdh_curve(SSL_CTX *ctx, char const *ecdh_curve, bool disable_single_dh_use)
 {
        int      nid;
        EC_KEY  *ecdh;
@@ -2163,7 +2397,9 @@ static int set_ecdh_curve(SSL_CTX *ctx, char const *ecdh_curve)
 
        SSL_CTX_set_tmp_ecdh(ctx, ecdh);
 
-       SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE);
+       if (!disable_single_dh_use) {
+               SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE);
+       }
 
        EC_KEY_free(ecdh);
 
@@ -2231,34 +2467,42 @@ void tls_global_init(void)
 int tls_global_version_check(char const *acknowledged)
 {
        uint64_t v;
+       bool bad = false;
+       size_t i;
+
+       if (strcmp(acknowledged, "yes") == 0) return 0;
 
-       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();
 
-               /* 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];
 
-               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)) {
+                       /*
+                        *      If the CVE is acknowledged, allow it.
+                        */
+                       if (!bad && (strcmp(acknowledged, defect->id) == 0)) return 0;
 
-                       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);
+                       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);
+
+                       /*
+                        *      Only warn about the first one...
+                        */
+                       if (!bad) {
+                               INFO("Once you have verified libssl has been correctly patched, "
+                                    "set security.allow_vulnerable_openssl = '%s'", defect->id);
 
                                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;
-               }
        }
 
+       if (bad) return -1;
+
        return 0;
 }
 #endif
@@ -2302,11 +2546,8 @@ SSL_CTX *tls_init_ctx(fr_tls_server_conf_t *conf, int client)
 
        ctx = SSL_CTX_new(SSLv23_method()); /* which is really "all known SSL / TLS methods".  Idiots. */
        if (!ctx) {
-               int err;
-               while ((err = ERR_get_error())) {
-                       ERROR(LOG_PREFIX ": Failed creating SSL context: %s", ERR_error_string(err, NULL));
-                       return NULL;
-               }
+               tls_error_log(NULL, "Failed creating TLS context");
+               return NULL;
        }
 
        /*
@@ -2465,15 +2706,14 @@ SSL_CTX *tls_init_ctx(fr_tls_server_conf_t *conf, int client)
 
        if (type == SSL_FILETYPE_PEM) {
                if (!(SSL_CTX_use_certificate_chain_file(ctx, conf->certificate_file))) {
-                       ERROR(LOG_PREFIX ": Error reading certificate file %s:%s", conf->certificate_file,
-                             ERR_error_string(ERR_get_error(), NULL));
+                       tls_error_log(NULL, "Failed reading certificate file \"%s\"",
+                                     conf->certificate_file);
                        return NULL;
                }
 
        } else if (!(SSL_CTX_use_certificate_file(ctx, conf->certificate_file, type))) {
-               ERROR(LOG_PREFIX ": Error reading certificate file %s:%s",
-                     conf->certificate_file,
-                     ERR_error_string(ERR_get_error(), NULL));
+               tls_error_log(NULL, "Failed reading certificate file \"%s\"",
+                             conf->certificate_file);
                return NULL;
        }
 
@@ -2481,8 +2721,8 @@ SSL_CTX *tls_init_ctx(fr_tls_server_conf_t *conf, int client)
 load_ca:
        if (conf->ca_file || conf->ca_path) {
                if (!SSL_CTX_load_verify_locations(ctx, conf->ca_file, conf->ca_path)) {
-                       ERROR(LOG_PREFIX ": SSL error %s", ERR_error_string(ERR_get_error(), NULL));
-                       ERROR(LOG_PREFIX ": Error reading Trusted root CA list %s",conf->ca_file );
+                       tls_error_log(NULL, "Failed reading Trusted root CA list \"%s\"",
+                                     conf->ca_file);
                        return NULL;
                }
        }
@@ -2490,9 +2730,8 @@ load_ca:
 
        if (conf->private_key_file) {
                if (!(SSL_CTX_use_PrivateKey_file(ctx, conf->private_key_file, type))) {
-                       ERROR(LOG_PREFIX ": Failed reading private key file %s:%s",
-                             conf->private_key_file,
-                             ERR_error_string(ERR_get_error(), NULL));
+                       tls_error_log(NULL, "Failed reading private key file \"%s\"",
+                                     conf->private_key_file);
                        return NULL;
                }
 
@@ -2530,9 +2769,11 @@ post_ca:
        ctx_tls_versions |= SSL_OP_NO_TLSv1_1;
 #endif
 #ifdef SSL_OP_NO_TLSv1_2
+
        if (conf->disable_tlsv1_2) ctx_options |= SSL_OP_NO_TLSv1_2;
 
        ctx_tls_versions |= SSL_OP_NO_TLSv1_2;
+
 #endif
 
        if ((ctx_options & ctx_tls_versions) == ctx_tls_versions) {
@@ -2544,16 +2785,16 @@ post_ca:
        ctx_options |= SSL_OP_NO_TICKET;
 #endif
 
-       /*
-        *      SSL_OP_SINGLE_DH_USE must be used in order to prevent
-        *      small subgroup attacks and forward secrecy. Always
-        *      using
-        *
-        *      SSL_OP_SINGLE_DH_USE has an impact on the computer
-        *      time needed during negotiation, but it is not very
-        *      large.
-        */
-       ctx_options |= SSL_OP_SINGLE_DH_USE;
+       if (!conf->disable_single_dh_use) {
+               /*
+                *      SSL_OP_SINGLE_DH_USE must be used in order to prevent
+                *      small subgroup attacks and forward secrecy. Always
+                *      using SSL_OP_SINGLE_DH_USE has an impact on the
+                *      computer time needed during negotiation, but it is not
+                *      very large.
+                */
+               ctx_options |= SSL_OP_SINGLE_DH_USE;
+       }
 
        /*
         *      SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS to work around issues
@@ -2584,12 +2825,22 @@ post_ca:
         */
 #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
 #ifndef OPENSSL_NO_ECDH
-       if (set_ecdh_curve(ctx, conf->ecdh_curve) < 0) {
+       if (set_ecdh_curve(ctx, conf->ecdh_curve, conf->disable_single_dh_use) < 0) {
                return NULL;
        }
 #endif
 #endif
 
+       /*
+        *      OpenSSL will automatically create certificate chains,
+        *      unless we tell it to not do that.  The problem is that
+        *      it sometimes gets the chains right from a certificate
+        *      signature view, but wrong from the clients view.
+        */
+       if (!conf->auto_chain) {
+               SSL_CTX_set_mode(ctx, SSL_MODE_NO_AUTO_CHAIN);
+       }
+
        /* Set Info callback */
        SSL_CTX_set_info_callback(ctx, cbtls_info);
 
@@ -2618,8 +2869,7 @@ post_ca:
        if (conf->check_crl) {
                certstore = SSL_CTX_get_cert_store(ctx);
                if (certstore == NULL) {
-                       ERROR(LOG_PREFIX ": SSL error %s", ERR_error_string(ERR_get_error(), NULL));
-                       ERROR(LOG_PREFIX ": Error reading Certificate Store");
+                       tls_error_log(NULL, "Error reading Certificate Store");
                        return NULL;
                }
                X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK);
@@ -2647,8 +2897,7 @@ post_ca:
        /* Load randomness */
        if (conf->random_file) {
                if (!(RAND_load_file(conf->random_file, 1024*10))) {
-                       ERROR(LOG_PREFIX ": SSL error %s", ERR_error_string(ERR_get_error(), NULL));
-                       ERROR(LOG_PREFIX ": Error loading randomness");
+                       tls_error_log(NULL, "Failed loading randomness");
                        return NULL;
                }
        }
@@ -2658,7 +2907,7 @@ post_ca:
         */
        if (conf->cipher_list) {
                if (!SSL_CTX_set_cipher_list(ctx, conf->cipher_list)) {
-                       ERROR(LOG_PREFIX ": Error setting cipher list");
+                       tls_error_log(NULL, "Failed setting cipher list");
                        return NULL;
                }
        }
@@ -2818,6 +3067,16 @@ fr_tls_server_conf_t *tls_server_conf_parse(CONF_SECTION *cs)
                goto error;
        }
 
+#ifdef SSL_OP_NO_TLSv1_2
+       /*
+        *      OpenSSL 1.0.1f and 1.0.1g get the MS-MPPE keys wrong.
+        */
+#if (OPENSSL_VERSION_NUMBER >= 0x10010060L) && (OPENSSL_VERSION_NUMBER < 0x10010060L)
+       conf->disable_tlsv1_2 = true;
+       WARN(LOG_PREFIX ": Disabling TLSv1.2 due to OpenSSL bugs");
+#endif
+#endif
+
        /*
         *      Cache conf in cs in case we're asked to parse this again.
         */
@@ -2895,7 +3154,7 @@ int tls_success(tls_session_t *ssn, REQUEST *request)
            (((vp = fr_pair_find_by_num(request->config, PW_ALLOW_SESSION_RESUMPTION, 0, TAG_ANY)) != NULL) &&
             (vp->vp_integer == 0))) {
                SSL_CTX_remove_session(ssn->ctx,
-                                      ssn->ssl->session);
+                                      ssn->ssl_session);
                ssn->allow_session_resumption = false;
 
                /*
@@ -2912,14 +3171,10 @@ int tls_success(tls_session_t *ssn, REQUEST *request)
         *      user data in the cache.
         */
        } else if (!SSL_session_reused(ssn->ssl)) {
-               size_t size;
                VALUE_PAIR **certs;
                char buffer[2 * MAX_SESSION_SIZE + 1];
 
-               size = ssn->ssl->session->session_id_length;
-               if (size > MAX_SESSION_SIZE) size = MAX_SESSION_SIZE;
-
-               fr_bin2hex(buffer, ssn->ssl->session->session_id, size);
+               tls_session_id(ssn->ssl_session, buffer, MAX_SESSION_SIZE);
 
                vp = fr_pair_list_copy_by_num(talloc_ctx, request->reply->vps, PW_USER_NAME, 0, TAG_ANY);
                if (vp) fr_pair_add(&vps, vp);
@@ -2955,7 +3210,7 @@ int tls_success(tls_session_t *ssn, REQUEST *request)
                }
 
                if (vps) {
-                       SSL_SESSION_set_ex_data(ssn->ssl->session, fr_tls_ex_index_vps, vps);
+                       SSL_SESSION_set_ex_data(ssn->ssl_session, fr_tls_ex_index_vps, vps);
                        rdebug_pair_list(L_DBG_LVL_2, request, vps, "  caching ");
 
                        if (conf->session_cache_path) {
@@ -3005,20 +3260,16 @@ int tls_success(tls_session_t *ssn, REQUEST *request)
                        }
                } else {
                        RDEBUG2("No information to cache: session caching will be disabled for session %s", buffer);
-                       SSL_CTX_remove_session(ssn->ctx, ssn->ssl->session);
+                       SSL_CTX_remove_session(ssn->ctx, ssn->ssl_session);
                }
 
        /*
         *      Else the session WAS allowed.  Copy the cached reply.
         */
        } else {
-               size_t size;
                char buffer[2 * MAX_SESSION_SIZE + 1];
 
-               size = ssn->ssl->session->session_id_length;
-               if (size > MAX_SESSION_SIZE) size = MAX_SESSION_SIZE;
-
-               fr_bin2hex(buffer, ssn->ssl->session->session_id, size);
+               tls_session_id(ssn->ssl_session, buffer, MAX_SESSION_SIZE);
 
                /*
                 *      The "restore VPs from OpenSSL cache" code is
@@ -3052,7 +3303,7 @@ void tls_fail(tls_session_t *ssn)
        /*
         *      Force the session to NOT be cached.
         */
-       SSL_CTX_remove_session(ssn->ctx, ssn->ssl->session);
+       SSL_CTX_remove_session(ssn->ctx, ssn->ssl_session);
 }
 
 fr_tls_status_t tls_application_data(tls_session_t *ssn, REQUEST *request)
@@ -3101,11 +3352,9 @@ fr_tls_status_t tls_application_data(tls_session_t *ssn, REQUEST *request)
                        break;
 
                default:
-                       DEBUG("Error in fragmentation logic: %s", ERR_error_string(code, NULL));
-
-                       /*
-                        *      FIXME: Call int_ssl_check?
-                        */
+                       REDEBUG("Error in fragmentation logic");
+                       tls_error_io_log(request, ssn, err,
+                                        "Failed in " STRINGIFY(__FUNCTION__) " (SSL_read)");
                        break;
                }
                return FR_TLS_FAIL;
index 61bc9c8..ccd9895 100644 (file)
@@ -33,6 +33,7 @@ USES_APPLE_DEPRECATED_API     /* OpenSSL API has been deprecated by Apple */
 #include <sys/stat.h>
 #endif
 
+#ifdef WITH_TCP
 #ifdef WITH_TLS
 #ifdef HAVE_OPENSSL_RAND_H
 #include <openssl/rand.h>
@@ -442,6 +443,11 @@ int dual_tls_send(rad_listen_t *listener, REQUEST *request)
                return 0;
        }
 
+       if (request->reply->data_len > (MAX_PACKET_LEN - 100)) {
+               RWARN("Packet is large, and possibly truncated - %zd vs max %d",
+                     request->reply->data_len, MAX_PACKET_LEN);
+       }
+
        /*
         *      Sign the packet.
         */
@@ -527,10 +533,7 @@ static ssize_t proxy_tls_read(rad_listen_t *listener)
                                return -1;
 
                        default:
-                               while ((err = ERR_get_error())) {
-                                       DEBUG("proxy recv says %s",
-                                             ERR_error_string(err, NULL));
-                               }
+                               tls_error_log(NULL, "Failed in proxy receive");
 
                                goto do_close;
                        }
@@ -712,8 +715,7 @@ int proxy_tls_send(rad_listen_t *listener, REQUEST *request)
                        break;  /* let someone else retry */
 
                default:
-                       DEBUG("proxy SSL_write says %s",
-                             ERR_error_string(err, NULL));
+                       tls_error_log(NULL, "Failed in proxy send");
                        DEBUG("Closing TLS socket to home server");
                        tls_socket_close(listener);
                        PTHREAD_MUTEX_UNLOCK(&sock->mutex);
@@ -727,3 +729,4 @@ int proxy_tls_send(rad_listen_t *listener, REQUEST *request)
 #endif /* WITH_PROXY */
 
 #endif /* WITH_TLS */
+#endif /* WITH_TCP */
index ae89b33..919cc86 100644 (file)
@@ -251,7 +251,7 @@ VALUE_PAIR **radius_list(REQUEST *request, pair_lists_t list)
                if (request->coa && /* match reply with request */
                    (request->coa->proxy->code == PW_CODE_DISCONNECT_REQUEST) &&
                    request->coa->proxy_reply) {
-                       return &request->coa->proxy->vps;
+                       return &request->coa->proxy_reply->vps;
                }
                break;
 #endif
@@ -300,11 +300,11 @@ RADIUS_PACKET *radius_packet(REQUEST *request, pair_lists_t list)
 #ifdef WITH_COA
        case PAIR_LIST_COA:
        case PAIR_LIST_DM:
-               return request->coa->packet;
+               return request->coa->proxy;
 
        case PAIR_LIST_COA_REPLY:
        case PAIR_LIST_DM_REPLY:
-               return request->coa->reply;
+               return request->coa->proxy_reply;
 #endif
        }
 
@@ -339,7 +339,7 @@ TALLOC_CTX *radius_list_ctx(REQUEST *request, pair_lists_t list)
                return request;
 
        case PAIR_LIST_STATE:
-               return request;
+               return request->state_ctx;
 
 #ifdef WITH_PROXY
        case PAIR_LIST_PROXY_REQUEST:
index 9952a8a..a09cef4 100644 (file)
@@ -37,10 +37,8 @@ RCSID("$Id$")
 /*
  *  Global variables.
  */
-char const *progname = NULL;
 char const *radacct_dir = NULL;
 char const *radlog_dir = NULL;
-char const *radlib_dir = NULL;
 bool log_stripped_names = false;
 
 static bool memory_report = false;
@@ -645,11 +643,6 @@ int main(int argc, char *argv[])
        }
 #endif
 
-       if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL)
-               progname = argv[0];
-       else
-               progname++;
-
        rad_debug_lvl = 0;
        set_radius_dir(NULL, RADIUS_DIR);
 
@@ -942,7 +935,7 @@ static void NEVER_RETURNS usage(int status)
 {
        FILE *output = status?stderr:stdout;
 
-       fprintf(output, "Usage: %s [options]\n", progname);
+       fprintf(output, "Usage: %s [options]\n", main_config.name);
        fprintf(output, "Options:\n");
        fprintf(output, "  -d raddb_dir  Configuration files are in \"raddb_dir/*\".\n");
        fprintf(output, "  -D dict_dir   Dictionary files are in \"dict_dir/*\".\n");
index cdc6ec0..09f3938 100644 (file)
@@ -19,3 +19,7 @@ TGT_PREREQS   := libfreeradius-server.a libfreeradius-radius.a
 ifneq "$(filter rlm_eap_%,${ALL_TGTS})" ""
 TGT_PREREQS    += libfreeradius-eap.a
 endif
+
+ifneq ($(MAKECMDGOALS),scan)
+SRC_CFLAGS     += -DBUILT_WITH_CPPFLAGS=\"$(CPPFLAGS)\" -DBUILT_WITH_CFLAGS=\"$(CFLAGS)\" -DBUILT_WITH_LDFLAGS=\"$(LDFLAGS)\" -DBUILT_WITH_LIBS=\"$(LIBS)\"
+endif
index 7b8c202..22299f8 100644 (file)
@@ -303,6 +303,7 @@ size_t rad_filename_make_safe(UNUSED REQUEST *request, char *out, size_t outlen,
                         */
                        if (*q < ' ') {
                                *(p++) = '_';
+                               q++;
                                continue;
                        }
 
@@ -580,6 +581,13 @@ static int _request_free(REQUEST *request)
        request->home_server = NULL;
 #endif
 
+       /*
+        *      This is parented separately.
+        */
+       if (request->state_ctx) {
+               talloc_free(request->state_ctx);
+       }
+
        return 0;
 }
 
@@ -613,6 +621,8 @@ REQUEST *request_alloc(TALLOC_CTX *ctx)
        request->component = "<core>";
        request->log.func = vradlog_request;
 
+       request->state_ctx = talloc_init("session-state");
+
        return request;
 }
 
@@ -1102,7 +1112,7 @@ void verify_request(char const *file, int line, REQUEST *request)
 
 #ifdef WITH_VERIFY_PTR
        fr_pair_list_verify(file, line, request, request->config);
-       fr_pair_list_verify(file, line, request, request->state);
+       fr_pair_list_verify(file, line, request->state_ctx, request->state);
 #endif
 
        if (request->packet) verify_packet(file, line, request, request->packet, "request");
index 4a4a156..fc3fa88 100644 (file)
@@ -496,7 +496,7 @@ void version_print(void)
        CONF_ITEM *ci;
        CONF_PAIR *cp;
 
-       if (DEBUG_ENABLED2) {
+       if (DEBUG_ENABLED3) {
                int max = 0, len;
 
                MEM(features = cf_section_alloc(NULL, "feature", NULL));
@@ -505,7 +505,7 @@ void version_print(void)
                MEM(versions = cf_section_alloc(NULL, "version", NULL));
                version_init_numbers(versions);
 
-               DEBUG3("Server was built with: ");
+               DEBUG2("Server was built with: ");
 
                for (ci = cf_item_find_next(features, NULL);
                     ci;
@@ -530,13 +530,13 @@ void version_print(void)
                        cp = cf_item_to_pair(ci);
                        attr = cf_pair_attr(cp);
 
-                       DEBUG3("  %s%.*s : %s", attr,
+                       DEBUG2("  %s%.*s : %s", attr,
                               (int)(max - talloc_array_length(attr)), spaces,  cf_pair_value(cp));
                }
 
                talloc_free(features);
 
-               DEBUG3("Server core libs:");
+               DEBUG2("Server core libs:");
 
                for (ci = cf_item_find_next(versions, NULL);
                     ci;
@@ -546,36 +546,38 @@ void version_print(void)
                        cp = cf_item_to_pair(ci);
                        attr = cf_pair_attr(cp);
 
-                       DEBUG3("  %s%.*s : %s", attr,
+                       DEBUG2("  %s%.*s : %s", attr,
                               (int)(max - talloc_array_length(attr)), spaces,  cf_pair_value(cp));
                }
 
                talloc_free(versions);
 
-               DEBUG3("Endianness:");
+               DEBUG2("Endianness:");
 #if defined(FR_LITTLE_ENDIAN)
-               DEBUG3("  little");
+               DEBUG2("  little");
 #elif defined(FR_BIG_ENDIAN)
-               DEBUG3("  big");
+               DEBUG2("  big");
 #else
-               DEBUG3("  unknown");
+               DEBUG2("  unknown");
 #endif
 
-               DEBUG3("Compilation flags:");
+               DEBUG2("Compilation flags:");
 #ifdef BUILT_WITH_CPPFLAGS
-               DEBUG3("  cppflags : " BUILT_WITH_CPPFLAGS);
+               DEBUG2("  cppflags : " BUILT_WITH_CPPFLAGS);
 #endif
 #ifdef BUILT_WITH_CFLAGS
-               DEBUG3("  cflags   : " BUILT_WITH_CFLAGS);
+               DEBUG2("  cflags   : " BUILT_WITH_CFLAGS);
 #endif
 #ifdef BUILT_WITH_LDFLAGS
-               DEBUG3("  ldflags  : " BUILT_WITH_LDFLAGS);
+               DEBUG2("  ldflags  : " BUILT_WITH_LDFLAGS);
 #endif
 #ifdef BUILT_WITH_LIBS
-               DEBUG3("  libs     : " BUILT_WITH_LIBS);
+               DEBUG2("  libs     : " BUILT_WITH_LIBS);
 #endif
+               DEBUG2("  ");
        }
-       INFO("Copyright (C) 1999-2015 The FreeRADIUS server project and contributors");
+       INFO("FreeRADIUS Version " RADIUSD_VERSION_STRING);
+       INFO("Copyright (C) 1999-2016 The FreeRADIUS server project and contributors");
        INFO("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A");
        INFO("PARTICULAR PURPOSE");
        INFO("You may redistribute copies of FreeRADIUS under the terms of the");
index 87c206f..d527015 100644 (file)
@@ -623,6 +623,10 @@ static ssize_t xlat_string(UNUSED void *instance, REQUEST *request,
                len = fr_prints(out, outlen, (char const *) p, vp->vp_length, '"');
                break;
 
+               /*
+                *      Note that "%{string:...}" is NOT binary safe!
+                *      It is explicitly used to get rid of embedded zeros.
+                */
        case PW_TYPE_STRING:
                len = strlcpy(out, vp->vp_strvalue, outlen);
                break;
@@ -653,6 +657,8 @@ static ssize_t xlat_xlat(UNUSED void *instance, REQUEST *request,
 
        if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) goto nothing;
 
+       if (vp->da->type != PW_TYPE_STRING) goto nothing;
+
        return radius_xlat(out, outlen, request, vp->vp_strvalue, NULL, NULL);
 }
 
@@ -2356,10 +2362,13 @@ static char *xlat_aprint(TALLOC_CTX *ctx, REQUEST *request, xlat_exp_t const * c
         *      Escape the non-literals we found above.
         */
        if (str && escape) {
+               size_t len;
                char *escaped;
 
-               escaped = talloc_array(ctx, char, 2048); /* FIXME: do something intelligent */
-               escape(request, escaped, 2038, str, escape_ctx);
+               len = talloc_array_length(str) * 3;
+
+               escaped = talloc_array(ctx, char, len);
+               escape(request, escaped, len, str, escape_ctx);
                talloc_free(str);
                str = escaped;
        }
diff --git a/src/modules/.gitignore b/src/modules/.gitignore
new file mode 100644 (file)
index 0000000..ead362f
--- /dev/null
@@ -0,0 +1,3 @@
+rlm_json
+rlm_winbind
+*_ext
index 6b47dcf..ea8369b 100644 (file)
@@ -331,7 +331,7 @@ RADIUS_PACKET *fr_dhcp_recv(int sockfd)
        packet->id = ntohl(magic);
 
        code = dhcp_get_option((dhcp_packet_t *) packet->data,
-                              packet->data_len, 53);
+                              packet->data_len, PW_DHCP_MESSAGE_TYPE);
        if (!code) {
                fr_strerror_printf("No message-type option was found in the packet");
                rad_free(&packet);
@@ -872,6 +872,16 @@ ssize_t fr_dhcp_decode_options(TALLOC_CTX *ctx, VALUE_PAIR **out, uint8_t const
                a_p = p + 2;
 
                /*
+                *      Ensure we've not been given a bad length value
+                */
+               if ((a_p + a_len) > q) {
+                       fr_strerror_printf("Length field value of option %u is incorrect.  "
+                                          "Got %u bytes, expected <= %zu bytes", p[0], p[1], q - a_p);
+                       fr_pair_list_free(out);
+                       return -1;
+               }
+
+               /*
                 *      Unknown attribute, create an octets type
                 *      attribute with the contents of the sub-option.
                 */
@@ -952,7 +962,6 @@ int fr_dhcp_decode(RADIUS_PACKET *packet)
         *      Decode the header.
         */
        for (i = 0; i < 14; i++) {
-               char *q;
 
                vp = fr_pair_make(packet, NULL, dhcp_header_names[i], NULL, T_OP_EQ);
                if (!vp) {
@@ -1005,14 +1014,18 @@ int fr_dhcp_decode(RADIUS_PACKET *packet)
                        break;
 
                case PW_TYPE_STRING:
-                       vp->vp_strvalue = q = talloc_array(vp, char, dhcp_header_sizes[i] + 1);
-                       vp->type = VT_DATA;
-                       memcpy(q, p, dhcp_header_sizes[i]);
-                       q[dhcp_header_sizes[i]] = '\0';
-                       vp->vp_length = strlen(vp->vp_strvalue);
-                       if (vp->vp_length == 0) {
-                               fr_pair_list_free(&vp);
+                       /*
+                        *      According to RFC 2131, these are null terminated strings.
+                        *      We don't trust everyone to abide by the RFC, though.
+                        */
+                       if (*p != '\0') {
+                               uint8_t *end;
+                               int len;
+                               end = memchr(p, '\0', dhcp_header_sizes[i]);
+                               len = end ? end - p : dhcp_header_sizes[i];
+                               fr_pair_value_bstrncpy(vp, p, len);
                        }
+                       if (vp->vp_length == 0) fr_pair_list_free(&vp);
                        break;
 
                case PW_TYPE_OCTETS:
@@ -1141,12 +1154,12 @@ int8_t fr_dhcp_attr_cmp(void const *a, void const *b)
        /*
         *      DHCP-Message-Type is first, for simplicity.
         */
-       if ((my_a->da->attr == 53) && (my_b->da->attr != 53)) return -1;
+       if ((my_a->da->attr == PW_DHCP_MESSAGE_TYPE) && (my_b->da->attr != PW_DHCP_MESSAGE_TYPE)) return -1;
 
        /*
         *      Relay-Agent is last
         */
-       if ((my_a->da->attr == 82) && (my_b->da->attr != 82)) return 1;
+       if ((my_a->da->attr == PW_DHCP_OPTION_82) && (my_b->da->attr != PW_DHCP_OPTION_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;
@@ -1323,7 +1336,7 @@ ssize_t fr_dhcp_encode_option(UNUSED TALLOC_CTX *ctx, uint8_t *out, size_t outle
        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 == PW_DHCP_MESSAGE_TYPE) 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) {
@@ -2047,7 +2060,7 @@ RADIUS_PACKET *fr_dhcp_recv_raw_packet(int sockfd, struct sockaddr_ll *p_ll, RAD
        packet->id = xid;
 
        code = dhcp_get_option((dhcp_packet_t *) packet->data,
-                              packet->data_len, 53);
+                              packet->data_len, PW_DHCP_MESSAGE_TYPE);
        if (!code) {
                fr_strerror_printf("No message-type option was found in the packet");
                rad_free(&packet);
index e9572bc..76ba6a4 100644 (file)
@@ -143,7 +143,8 @@ static void CC_HINT(nonnull) cache_merge(rlm_cache_t *inst, REQUEST *request, rl
 
        if (c->state) {
                rdebug_pair_list(L_DBG_LVL_2, request, c->state, "&session-state:");
-               radius_pairmove(request, &request->state, fr_pair_list_copy(request->state, c->state), false);
+
+               fr_pair_list_mcopy_by_num(request->state_ctx, &request->state, &c->state, 0, 0, TAG_ANY);
        }
 
        if (inst->stats) {
index 4f79fe3..f338167 100644 (file)
@@ -59,7 +59,7 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(UNUSED void *instance, REQU
        uint8_t pass_str[MAX_STRING_LEN];
 
        if (!request->username) {
-               RWDEBUG("&request:User-Name attribute is required for authentication");
+               REDEBUG("&request:User-Name attribute is required for authentication");
                return RLM_MODULE_INVALID;
        }
 
index a73244c..43ef1f8 100644 (file)
@@ -478,13 +478,13 @@ static rlm_rcode_t mod_checksimul(void *instance, REQUEST *request) {
 
        /* do nothing if this is not enabled */
        if (inst->check_simul != true) {
-               RDEBUG3("mod_checksimul returning noop - not enabled");
+               RWDEBUG("Simultaneous-Use checking requires 'simul_count_query' to be configured");
                return RLM_MODULE_NOOP;
        }
 
        /* ensure valid username in request */
-       if ((!request->username) || (request->username->vp_length == '\0')) {
-               RDEBUG3("mod_checksimul - invalid username");
+       if ((!request->username) || (request->username->vp_length == 0)) {
+               REDEBUG("Zero Length username not permitted");
                return RLM_MODULE_INVALID;
        }
 
index 0da346f..5570dd4 100644 (file)
@@ -10,8 +10,8 @@ SRC_CFLAGS    := @mod_cflags@
 TGT_LDLIBS     := @mod_ldflags@
 
 ifneq "$(TARGETNAME)" ""
-install: install.bindir $(R)$(bindir)/rad_counter
+install: $(R)$(bindir)/rad_counter
 
-$(R)$(bindir)/rad_counter: src/modules/rlm_counter/rad_counter
+$(R)$(bindir)/rad_counter: src/modules/rlm_counter/rad_counter | $(R)$(bindir)
        @$(INSTALL) -m 755 src/modules/rlm_counter/rad_counter $(R)$(bindir)/
 endif
index 6442238..cc9bd6c 100644 (file)
@@ -132,7 +132,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                inst->escape_func = rad_filename_make_safe;
        }
 
-       inst->ef = exfile_init(inst, 64, 30, inst->locking);
+       inst->ef = exfile_init(inst, 256, 30, inst->locking);
        if (!inst->ef) {
                cf_log_err_cs(conf, "Failed creating log file context");
                return -1;
index 22a29b8..572e04d 100644 (file)
@@ -108,7 +108,6 @@ static int digest_fix(REQUEST *request)
                int length = i->vp_length;
                int attrlen;
                uint8_t const *p = &i->vp_octets[0];
-               char *q;
                VALUE_PAIR *sub;
 
                /*
@@ -149,10 +148,7 @@ static int digest_fix(REQUEST *request)
                         */
                        sub = radius_pair_create(request->packet, &request->packet->vps,
                                                PW_DIGEST_REALM - 1 + p[0], 0);
-                       sub->vp_length = attrlen - 2;
-                       sub->vp_strvalue = q = talloc_array(sub, char, sub->vp_length + 1);
-                       memcpy(q, p + 2, attrlen - 2);
-                       q[attrlen - 2] = '\0';
+                       fr_pair_value_bstrncpy(sub, p + 2, attrlen - 2);
 
                        if ((rad_debug_lvl > 1) && fr_log_fp) {
                                vp_print(fr_log_fp, sub);
index 6b979cc..d9660ed 100644 (file)
@@ -122,11 +122,6 @@ int eap_module_instantiate(rlm_eap_t *inst, eap_module_t **m_inst, eap_type_t nu
                p++;
        }
 
-#if defined(HAVE_DLFCN_H) && defined(RTLD_SELF)
-       method->type = dlsym(RTLD_SELF, mod_name);
-       if (method->type) goto open_self;
-#endif
-
        /*
         *      Link the loaded EAP-Type
         */
@@ -145,9 +140,6 @@ int eap_module_instantiate(rlm_eap_t *inst, eap_module_t **m_inst, eap_type_t nu
                return -1;
        }
 
-#if !defined(WITH_LIBLTDL) && defined(HAVE_DLFCN_H) && defined(RTLD_SELF)
-open_self:
-#endif
        cf_log_module(cs, "Linked to sub-module %s", mod_name);
 
        /*
@@ -275,7 +267,7 @@ static eap_type_t eap_process_nak(rlm_eap_t *inst, REQUEST *request,
                if ((nak->data[i] >= PW_EAP_MAX_TYPES) ||
                    !inst->methods[nak->data[i]]) {
                        RDEBUG2("Peer NAK'd asking for "
-                               "unsupported type %s (%d), skipping...",
+                               "unsupported EAP type %s (%d), skipping...",
                                eap_type2name(nak->data[i]),
                                nak->data[i]);
 
@@ -294,6 +286,12 @@ static eap_type_t eap_process_nak(rlm_eap_t *inst, REQUEST *request,
                                eap_type2name(nak->data[i]),
                                nak->data[i]);
 
+                       RWARN("!!! We requested to use an EAP type as normal.");
+                       RWARN("!!! The supplicant rejected that, and requested to use the same EAP type.");
+                       RWARN("!!!     i.e. the supplicant said 'I don't like X, please use X instead.");
+                       RWARN("!!! The supplicant software is broken and does not work properly.");
+                       RWARN("!!! Please upgrade it to software that works.");
+
                        continue;
                }
 
@@ -356,10 +354,19 @@ eap_rcode_t eap_method_select(rlm_eap_t *inst, eap_handler_t *handler)
        }
 
        /*
-        *      Multiple levels of nesting are invalid.
+        *      Multiple levels of TLS nesting are invalid.  But if
+        *      the parent has a home_server defined, then this
+        *      request is being processed through a virtual
+        *      server... so that's OK.
+        *
+        *      i.e. we're inside an EAP tunnel, which means we have a
+        *      parent.  If the outer session exists, and doesn't have
+        *      a home server, then it's multiple layers of tunneling.
         */
-       if (handler->request->parent && handler->request->parent->parent) {
-               RDEBUG2("Multiple levels of TLS nesting is invalid");
+       if (handler->request->parent &&
+           handler->request->parent->parent &&
+           !handler->request->parent->parent->home_server) {
+               RERROR("Multiple levels of TLS nesting are invalid");
 
                return EAP_INVALID;
        }
@@ -383,7 +390,8 @@ eap_rcode_t eap_method_select(rlm_eap_t *inst, eap_handler_t *handler)
                if ((next < PW_EAP_MD5) ||
                    (next >= PW_EAP_MAX_TYPES) ||
                    (!inst->methods[next])) {
-                       REDEBUG2("Tried to start unsupported method (%d)", next);
+                       REDEBUG2("Tried to start unsupported EAP type %s (%d)",
+                                eap_type2name(next), next);
 
                        return EAP_INVALID;
                }
@@ -437,7 +445,7 @@ eap_rcode_t eap_method_select(rlm_eap_t *inst, eap_handler_t *handler)
                         *      We haven't configured it, it doesn't exit.
                         */
                        if (!inst->methods[type->num]) {
-                               REDEBUG2("Client asked for unsupported method %s (%d)",
+                               REDEBUG2("Client asked for unsupported EAP type %s (%d)",
                                         eap_type2name(type->num),
                                         type->num);
 
@@ -933,7 +941,8 @@ static int eap_validation(REQUEST *request, eap_packet_raw_t **eap_packet_p)
 
                        if ((eap_packet->data[7] == 0) ||
                            (eap_packet->data[7] >= PW_EAP_MAX_TYPES)) {
-                               RAUTH("Unsupported Expanded EAP type %u: ignoring the packet", eap_packet->data[7]);
+                               RAUTH("Unsupported Expanded EAP type %s (%u): ignoring the packet",
+                                     eap_type2name(eap_packet->data[7]), eap_packet->data[7]);
                                return EAP_INVALID;
                        }
 
@@ -950,7 +959,8 @@ static int eap_validation(REQUEST *request, eap_packet_raw_t **eap_packet_p)
 
                        p = talloc_realloc(talloc_parent(eap_packet), eap_packet, uint8_t, len - 7);
                        if (!p) {
-                               RAUTH("Unsupported EAP type %u: ignoring the packet", eap_packet->data[0]);
+                               RAUTH("Unsupported EAP type %s (%u): ignoring the packet",
+                                     eap_type2name(eap_packet->data[0]), eap_packet->data[0]);
                                return EAP_INVALID;
                        }
 
@@ -965,7 +975,8 @@ static int eap_validation(REQUEST *request, eap_packet_raw_t **eap_packet_p)
                        return EAP_VALID;
                }
 
-               RAUTH("Unsupported EAP type %u: ignoring the packet", eap_packet->data[0]);
+               RAUTH("Unsupported EAP type %s (%u): ignoring the packet",
+                     eap_type2name(eap_packet->data[0]), eap_packet->data[0]);
                return EAP_INVALID;
        }
 
@@ -999,12 +1010,12 @@ static char *eap_identity(REQUEST *request, eap_handler_t *handler, eap_packet_r
        len = ntohs(len);
 
        if ((len <= 5) || (eap_packet->data[1] == 0x00)) {
-               RDEBUG("EAP-Identity Unknown");
+               REDEBUG("EAP-Identity Unknown");
                return NULL;
        }
 
        if (len > 1024) {
-               RDEBUG("EAP-Identity too long");
+               REDEBUG("EAP-Identity too long");
                return NULL;
        }
 
index 8ad8564..3f0fd73 100644 (file)
@@ -166,7 +166,7 @@ PW_CODE chbind_process(REQUEST *request, CHBIND_REQ *chbind)
 
        /* Set-up the fake request */
        fake = request_alloc_fake(request);
-       pair_make_request("Freeradius-Proxied-To", "127.0.0.1", T_OP_EQ);
+       fr_pair_make(fake->packet, &fake->packet->vps, "Freeradius-Proxied-To", "127.0.0.1", T_OP_EQ);
 
        /* Add the username to the fake request */
        if (chbind->username) {
index 2846e1d..fadc72c 100644 (file)
@@ -901,19 +901,16 @@ fr_tls_status_t eaptls_process(eap_handler_t *handler)
        status = eaptls_operation(status, handler);
        if (status == FR_TLS_SUCCESS) {
 #define MAX_SESSION_SIZE (256)
-               size_t size;
                VALUE_PAIR *vps;
                char buffer[2 * MAX_SESSION_SIZE + 1];
+
                /*
                 *      Restore the cached VPs before processing the
                 *      application data.
                 */
-               size = tls_session->ssl->session->session_id_length;
-               if (size > MAX_SESSION_SIZE) size = MAX_SESSION_SIZE;
-
-               fr_bin2hex(buffer, tls_session->ssl->session->session_id, size);
+               tls_session_id(tls_session->ssl_session, buffer, MAX_SESSION_SIZE);
 
-               vps = SSL_SESSION_get_ex_data(tls_session->ssl->session, fr_tls_ex_index_vps);
+               vps = SSL_SESSION_get_ex_data(tls_session->ssl_session, fr_tls_ex_index_vps);
                if (!vps) {
                        RWDEBUG("No information in cached session %s", buffer);
                } else {
index 7510cf6..9c357e2 100644 (file)
@@ -63,9 +63,11 @@ int  eaptls_request(EAP_DS *eap_ds, tls_session_t *ssn) CC_HINT(nonnull);
 
 
 /* MPPE key generation */
+void                   T_PRF(unsigned char const *secret, unsigned int secret_len, char const *prf_label, unsigned char const *seed,  unsigned int seed_len, unsigned char *out, unsigned int out_len) CC_HINT(nonnull(1,3,6));
 void   eaptls_gen_mppe_keys(REQUEST *request, SSL *s, char const *prf_label);
 void   eapttls_gen_challenge(SSL *s, uint8_t *buffer, size_t size);
 void   eaptls_gen_eap_key(RADIUS_PACKET *packet, SSL *s, uint32_t header);
+void                   eap_fast_tls_gen_challenge(SSL *ssl, uint8_t *buffer, uint8_t *scratch, size_t size, char const *prf_label) CC_HINT(nonnull);
 
 #define BUFFER_SIZE 1024
 
index 19a7596..8f7fc39 100644 (file)
@@ -293,12 +293,13 @@ int unmap_eapsim_basictypes(RADIUS_PACKET *r,
 
        /* big enough to have even a single attribute */
        if (attrlen < 5) {
-               ERROR("eap: EAP-Sim attribute too short: %d < 5", attrlen);
+               fr_strerror_printf("EAP-Sim attribute too short: %d < 5", attrlen);
                return 0;
        }
 
        newvp = fr_pair_afrom_num(r, PW_EAP_SIM_SUBTYPE, 0);
        if (!newvp) {
+               fr_strerror_printf("Failed creating EAP-SIM-Subtype");
                return 0;
        }
 
@@ -314,7 +315,7 @@ int unmap_eapsim_basictypes(RADIUS_PACKET *r,
                uint8_t *p;
 
                if(attrlen < 2) {
-                       ERROR("eap: EAP-Sim attribute %d too short: %d < 2", es_attribute_count, attrlen);
+                       fr_strerror_printf("EAP-Sim attribute %d too short: %d < 2", es_attribute_count, attrlen);
                        return 0;
                }
 
@@ -322,9 +323,8 @@ int unmap_eapsim_basictypes(RADIUS_PACKET *r,
                eapsim_len = attr[1] * 4;
 
                if (eapsim_len > attrlen) {
-                       ERROR("eap: EAP-Sim attribute %d (no.%d) has length longer than data (%d > %d)",
-                             eapsim_attribute, es_attribute_count, eapsim_len, attrlen);
-
+                       fr_strerror_printf("EAP-Sim attribute %d (no.%d) has length longer than data (%d > %d)",
+                                          eapsim_attribute, es_attribute_count, eapsim_len, attrlen);
                        return 0;
                }
 
@@ -332,9 +332,9 @@ int unmap_eapsim_basictypes(RADIUS_PACKET *r,
                        eapsim_len = MAX_STRING_LEN;
                }
                if (eapsim_len < 2) {
-                       ERROR("eap: EAP-Sim attribute %d (no.%d) has length too small", eapsim_attribute,
-                             es_attribute_count);
-                              return 0;
+                       fr_strerror_printf("EAP-Sim attribute %d (no.%d) has length too small", eapsim_attribute,
+                                          es_attribute_count);
+                       return 0;
                }
 
                newvp = fr_pair_afrom_num(r, eapsim_attribute+PW_EAP_SIM_BASE, 0);
@@ -349,6 +349,7 @@ int unmap_eapsim_basictypes(RADIUS_PACKET *r,
                attrlen -= eapsim_len;
                es_attribute_count++;
        }
+
        return 1;
 }
 
index 7fa92bd..88db26e 100644 (file)
@@ -29,7 +29,6 @@ USES_APPLE_DEPRECATED_API     /* OpenSSL API has been deprecated by Apple */
 #include <openssl/hmac.h>
 
 
-#if OPENSSL_VERSION_NUMBER < 0x10001000L
 /*
  * TLS PRF from RFC 2246
  */
@@ -44,6 +43,10 @@ static void P_hash(EVP_MD const *evp_md,
 
        HMAC_CTX_init(&ctx_a);
        HMAC_CTX_init(&ctx_out);
+#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
+       HMAC_CTX_set_flags(&ctx_a, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+       HMAC_CTX_set_flags(&ctx_out, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+#endif
        HMAC_Init_ex(&ctx_a, secret, secret_len, evp_md, NULL);
        HMAC_Init_ex(&ctx_out, secret, secret_len, evp_md, NULL);
 
@@ -82,6 +85,49 @@ static void P_hash(EVP_MD const *evp_md,
        memset(a, 0, sizeof(a));
 }
 
+/*  EAP-FAST Pseudo-Random Function (T-PRF): RFC 4851, Section 5.5 */
+void T_PRF(unsigned char const *secret, unsigned int secret_len,
+          char const *prf_label,
+          unsigned char const *seed,  unsigned int seed_len,
+          unsigned char *out, unsigned int out_len)
+{
+       size_t prf_size = strlen(prf_label);
+       size_t pos;
+       uint8_t *buf;
+
+       if (prf_size > 128) prf_size = 128;
+       prf_size++;     /* include trailing zero */
+
+       buf = talloc_size(NULL, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1);
+
+       memcpy(buf + SHA1_DIGEST_LENGTH, prf_label, prf_size);
+       if (seed) memcpy(buf + SHA1_DIGEST_LENGTH + prf_size, seed, seed_len);
+       *(uint16_t *)&buf[SHA1_DIGEST_LENGTH + prf_size + seed_len] = htons(out_len);
+       buf[SHA1_DIGEST_LENGTH + prf_size + seed_len + 2] = 1;
+
+       // T1 is just the seed
+       fr_hmac_sha1(buf, buf + SHA1_DIGEST_LENGTH, prf_size + seed_len + 2 + 1, secret, secret_len);
+
+#define MIN(a,b) (((a)>(b)) ? (b) : (a))
+       memcpy(out, buf, MIN(out_len, SHA1_DIGEST_LENGTH));
+
+       pos = SHA1_DIGEST_LENGTH;
+       while (pos < out_len) {
+               buf[SHA1_DIGEST_LENGTH + prf_size + seed_len + 2]++;
+
+               fr_hmac_sha1(buf, buf, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1, secret, secret_len);
+               memcpy(&out[pos], buf, MIN(out_len - pos, SHA1_DIGEST_LENGTH));
+
+               if (out_len - pos <= SHA1_DIGEST_LENGTH)
+                       break;
+
+               pos += SHA1_DIGEST_LENGTH;
+       }
+
+       memset(buf, 0, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1);
+       talloc_free(buf);
+}
+
 static void PRF(unsigned char const *secret, unsigned int secret_len,
                unsigned char const *seed,   unsigned int seed_len,
                unsigned char *out, unsigned char *buf, unsigned int out_len)
@@ -98,7 +144,6 @@ static void PRF(unsigned char const *secret, unsigned int secret_len,
                out[i] ^= buf[i];
        }
 }
-#endif
 
 #define EAPTLS_MPPE_KEY_LEN     32
 
@@ -111,11 +156,6 @@ void eaptls_gen_mppe_keys(REQUEST *request, SSL *s, char const *prf_label)
        uint8_t *p;
        size_t prf_size;
 
-       if (!s->s3) {
-               ERROR("No SSLv3 information");
-               return;
-       }
-
        prf_size = strlen(prf_label);
 
 #if OPENSSL_VERSION_NUMBER >= 0x10001000L
@@ -165,21 +205,15 @@ void eaptls_gen_mppe_keys(REQUEST *request, SSL *s, char const *prf_label)
  */
 void eapttls_gen_challenge(SSL *s, uint8_t *buffer, size_t size)
 {
-#if OPENSSL_VERSION_NUMBER < 0x10001000L
-       uint8_t out[32], buf[32];
-       uint8_t seed[sizeof(FR_TLS_PRF_CHALLENGE)-1 + 2*SSL3_RANDOM_SIZE];
-       uint8_t *p = seed;
-#endif
-
-       if (!s->s3) {
-               ERROR("No SSLv3 information");
-               return;
-       }
-
 #if OPENSSL_VERSION_NUMBER >= 0x10001000L
        SSL_export_keying_material(s, buffer, size, FR_TLS_PRF_CHALLENGE,
                                   sizeof(FR_TLS_PRF_CHALLENGE) - 1, NULL, 0, 0);
+
 #else
+       uint8_t out[32], buf[32];
+       uint8_t seed[sizeof(FR_TLS_PRF_CHALLENGE)-1 + 2*SSL3_RANDOM_SIZE];
+       uint8_t *p = seed;
+
        memcpy(p, FR_TLS_PRF_CHALLENGE, sizeof(FR_TLS_PRF_CHALLENGE)-1);
        p += sizeof(FR_TLS_PRF_CHALLENGE)-1;
        memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
@@ -188,7 +222,6 @@ void eapttls_gen_challenge(SSL *s, uint8_t *buffer, size_t size)
 
        PRF(s->session->master_key, s->session->master_key_length,
            seed, sizeof(seed), out, buf, sizeof(out));
-
        memcpy(buffer, out, size);
 #endif
 }
@@ -202,11 +235,6 @@ void eaptls_gen_eap_key(RADIUS_PACKET *packet, SSL *s, uint32_t header)
        VALUE_PAIR *vp;
        uint8_t *p;
 
-       if (!s->s3) {
-               ERROR("No SSLv3 information");
-               return;
-       }
-
        vp = fr_pair_afrom_num(packet, PW_EAP_SESSION_ID, 0);
        if (!vp) return;
 
@@ -214,9 +242,40 @@ void eaptls_gen_eap_key(RADIUS_PACKET *packet, SSL *s, uint32_t header)
        p = talloc_array(vp, uint8_t, vp->vp_length);
 
        p[0] = header & 0xff;
+
+#ifdef HAVE_SSL_GET_CLIENT_RANDOM
+       SSL_get_client_random(s, p + 1, SSL3_RANDOM_SIZE);
+       SSL_get_server_random(s, p + 1 + SSL3_RANDOM_SIZE, SSL3_RANDOM_SIZE);
+#else
        memcpy(p + 1, s->s3->client_random, SSL3_RANDOM_SIZE);
        memcpy(p + 1 + SSL3_RANDOM_SIZE,
               s->s3->server_random, SSL3_RANDOM_SIZE);
+#endif
        vp->vp_octets = p;
        fr_pair_add(&packet->vps, vp);
 }
+
+/*
+ *     Same as before, but for EAP-FAST the order of {server,client}_random is flipped
+ */
+void eap_fast_tls_gen_challenge(SSL *s, uint8_t *buffer, uint8_t *scratch, size_t size, char const *prf_label)
+{
+       uint8_t seed[128 + 2*SSL3_RANDOM_SIZE];
+       uint8_t *p = seed;
+       size_t len;
+
+       len = strlen(prf_label);
+       if (len > 128) len = 128;
+
+       memcpy(p, prf_label, len);
+       p += len;
+       memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
+       p += SSL3_RANDOM_SIZE;
+       memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
+       p += SSL3_RANDOM_SIZE;
+
+       PRF(s->session->master_key, s->session->master_key_length,
+           seed, p - seed, buffer, scratch, size);
+}
+
+
index 7d9d62c..c0899f0 100644 (file)
@@ -406,8 +406,14 @@ eap_handler_t *eaplist_find(rlm_eap_t *inst, REQUEST *request,
         *      must exist.
         */
        state = fr_pair_find_by_num(request->packet->vps, PW_STATE, 0, TAG_ANY);
-       if (!state ||
-           (state->vp_length != EAP_STATE_LEN)) {
+       if (!state) {
+               REDEBUG("EAP requires the State attribute to work, but no State exists in the Access-Request packet.");
+               REDEBUG("The RADIUS client is broken.  No amount of changing FreeRADIUS will fix the RADIUS client.");
+               return NULL;
+       }
+
+       if (state->vp_length != EAP_STATE_LEN) {
+               REDEBUG("The RADIUS client has mangled the State attribute, OR you are forcing EAP in the wrong situation");
                return NULL;
        }
 
index 5cc5fa5..020d252 100644 (file)
@@ -55,7 +55,7 @@ static int totalapp = 0;
 static int totaldeny = 0;
 static char filesecret[256];
 static char const *radius_dir = NULL;
-char const *progname = "radeapclient";
+static char const *progname = "radeapclient";
 /* fr_randctx randctx; */
 
 main_config_t main_config;
index fe86f7d..6068f54 100644 (file)
@@ -21,4 +21,9 @@ endif
 
 SRC_CFLAGS += -DWITH_EAPCLIENT
 SRC_INCDIRS  := ${top_srcdir}/src/modules/rlm_eap/libeap
+
+ifneq ($(MAKECMDGOALS),scan)
+SRC_CFLAGS     += -DBUILT_WITH_CPPFLAGS=\"$(CPPFLAGS)\" -DBUILT_WITH_CFLAGS=\"$(CFLAGS)\" -DBUILT_WITH_LDFLAGS=\"$(LDFLAGS)\" -DBUILT_WITH_LIBS=\"$(LIBS)\"
+endif
+
 endif
index 5afdcc3..8c5f3c1 100644 (file)
@@ -113,6 +113,12 @@ static int mod_instantiate(CONF_SECTION *cs, void *instance)
        inst->xlat_name = cf_section_name2(cs);
        if (!inst->xlat_name) inst->xlat_name = "EAP";
 
+       if (!dict_valbyname(PW_AUTH_TYPE, 0, inst->xlat_name)) {
+               cf_log_err_cs(cs, "Failed to find 'Auth-Type %s' section.  Cannot authenticate users.",
+                             inst->xlat_name);
+               return -1;
+       }
+
        /* Load all the configured EAP-Types */
        num_methods = 0;
        for(scs = cf_subsection_find_next(cs, NULL, NULL);
@@ -155,12 +161,17 @@ static int mod_instantiate(CONF_SECTION *cs, void *instance)
                 *      etc. configurations from eap.conf in order to
                 *      have EAP without the TLS types.
                 */
-               if ((method == PW_EAP_TLS) ||
-                   (method == PW_EAP_TTLS) ||
-                   (method == PW_EAP_PEAP)) {
-                       DEBUG2("rlm_eap (%s): Ignoring EAP method %s because we do not have OpenSSL support",
-                              inst->xlat_name, name);
+               switch (method) {
+               case PW_EAP_TLS:
+               case PW_EAP_TTLS:
+               case PW_EAP_PEAP:
+               case PW_EAP_PWD:
+                       WARN("rlm_eap (%s): Ignoring EAP method %s because we don't have OpenSSL support",
+                            inst->xlat_name, name);
                        continue;
+
+               default:
+                       break;
                }
 #endif
 
@@ -243,8 +254,8 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *re
        inst = (rlm_eap_t *) instance;
 
        if (!fr_pair_find_by_num(request->packet->vps, PW_EAP_MESSAGE, 0, TAG_ANY)) {
-               REDEBUG("You set 'Auth-Type = EAP' for a request that does "
-                       "not contain an EAP-Message attribute!");
+               REDEBUG("You set 'Auth-Type = %s' for a request that does "
+                       "not contain an EAP-Message attribute!", inst->xlat_name);
                return RLM_MODULE_INVALID;
        }
 
@@ -346,7 +357,7 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *re
                 */
                fr_pair_delete_by_num(&request->proxy->vps, PW_FREERADIUS_PROXIED_TO, VENDORPEC_FREERADIUS, TAG_ANY);
 
-               RDEBUG2("Tunneled session will be proxied.  Not doing EAP");
+               RWDEBUG2("Tunneled session will be proxied.  Not doing EAP");
                return RLM_MODULE_HANDLED;
        }
 #endif
@@ -518,6 +529,7 @@ static rlm_rcode_t CC_HINT(nonnull) mod_post_proxy(void *inst, REQUEST *request)
 {
        size_t          i;
        size_t          len;
+       ssize_t         ret;
        char            *p;
        VALUE_PAIR      *vp;
        eap_handler_t   *handler;
@@ -660,18 +672,30 @@ static rlm_rcode_t CC_HINT(nonnull) mod_post_proxy(void *inst, REQUEST *request)
        i = 34;
        p = talloc_memdup(vp, vp->vp_strvalue, vp->vp_length + 1);
        talloc_set_type(p, uint8_t);
-       len = rad_tunnel_pwdecode((uint8_t *)p + 17, &i, request->home_server->secret, request->proxy->vector);
+       ret = rad_tunnel_pwdecode((uint8_t *)p + 17, &i, request->home_server->secret, request->proxy->vector);
+       if (ret < 0) {
+               REDEBUG("Decoding leap:session-key failed");
+               talloc_free(p);
+               return RLM_MODULE_FAIL;
+       }
+       len = i;
 
-       /*
-        *      FIXME: Assert that i == 16.
-        */
+       if (i != 16) {
+               REDEBUG("Decoded key length is incorrect, must be 16 bytes");
+               talloc_free(p);
+               return RLM_MODULE_FAIL;
+       }
 
        /*
         *      Encrypt the session key again, using the request data.
         */
-       rad_tunnel_pwencode(p + 17, &len,
-                           request->client->secret,
-                           request->packet->vector);
+       ret = rad_tunnel_pwencode(p + 17, &len, request->client->secret, request->packet->vector);
+       if (ret < 0) {
+               REDEBUG("Decoding leap:session-key failed");
+               talloc_free(p);
+               return RLM_MODULE_FAIL;
+       }
+
        fr_pair_value_strsteal(vp, p);
 
        return RLM_MODULE_UPDATED;
diff --git a/src/modules/rlm_eap/types/rlm_eap_fast/all.mk b/src/modules/rlm_eap/types/rlm_eap_fast/all.mk
new file mode 100644 (file)
index 0000000..aae64bc
--- /dev/null
@@ -0,0 +1,10 @@
+TARGETNAME     := rlm_eap_fast
+
+ifneq "$(OPENSSL_LIBS)" ""
+TARGET         := $(TARGETNAME).a
+endif
+
+SOURCES                := $(TARGETNAME).c eap_fast.c eap_fast_crypto.c
+
+SRC_INCDIRS    := ${top_srcdir}/src/modules/rlm_eap/ ${top_srcdir}/src/modules/rlm_eap/libeap/
+TGT_PREREQS    := libfreeradius-eap.a
diff --git a/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.c b/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.c
new file mode 100644 (file)
index 0000000..32380c4
--- /dev/null
@@ -0,0 +1,1285 @@
+/*
+ * eap_fast.c  contains the interfaces that are called from the main handler
+ *
+ * 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 2016 Alan DeKok <aland@freeradius.org>
+ *   Copyright 2016 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include "eap_fast.h"
+#include "eap_fast_crypto.h"
+#include <freeradius-devel/sha1.h>
+#include <openssl/ssl.h>
+#include <openssl/rand.h>
+
+#define RANDFILL(x) do { rad_assert(sizeof(x) % sizeof(uint32_t) == 0); for (size_t i = 0; i < sizeof(x); i += sizeof(uint32_t)) *((uint32_t *)&x[i]) = fr_rand(); } while(0)
+
+/*
+ * Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
+ * All Rights Reserved.
+ *
+ * These programs are licensed under the BSD license (the one with
+ * advertisement clause removed).
+ *
+ * this function shamelessly stolen from from hostap:src/crypto/tls_openssl.c
+ */
+static int openssl_get_keyblock_size(REQUEST *request, SSL *ssl)
+{
+       const EVP_CIPHER *c;
+       const EVP_MD *h;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+       int md_size;
+
+       if (ssl->enc_read_ctx == NULL || ssl->enc_read_ctx->cipher == NULL ||
+           ssl->read_hash == NULL)
+               return -1;
+
+       c = ssl->enc_read_ctx->cipher;
+       h = EVP_MD_CTX_md(ssl->read_hash);
+       if (h)
+               md_size = EVP_MD_size(h);
+       else if (ssl->s3)
+               md_size = ssl->s3->tmp.new_mac_secret_size;
+       else
+               return -1;
+
+       RDEBUG2("OpenSSL: keyblock size: key_len=%d MD_size=%d "
+                  "IV_len=%d", EVP_CIPHER_key_length(c), md_size,
+                  EVP_CIPHER_iv_length(c));
+       return 2 * (EVP_CIPHER_key_length(c) +
+                   md_size +
+                   EVP_CIPHER_iv_length(c));
+#else
+       const SSL_CIPHER *ssl_cipher;
+       int cipher, digest;
+
+       ssl_cipher = SSL_get_current_cipher(ssl);
+       if (!ssl_cipher)
+               return -1;
+       cipher = SSL_CIPHER_get_cipher_nid(ssl_cipher);
+       digest = SSL_CIPHER_get_digest_nid(ssl_cipher);
+       RDEBUG2("OpenSSL: cipher nid %d digest nid %d", cipher, digest);
+       if (cipher < 0 || digest < 0)
+               return -1;
+       c = EVP_get_cipherbynid(cipher);
+       h = EVP_get_digestbynid(digest);
+       if (!c || !h)
+               return -1;
+
+       RDEBUG2("OpenSSL: keyblock size: key_len=%d MD_size=%d IV_len=%d",
+                  EVP_CIPHER_key_length(c), EVP_MD_size(h),
+                  EVP_CIPHER_iv_length(c));
+       return 2 * (EVP_CIPHER_key_length(c) + EVP_MD_size(h) +
+                   EVP_CIPHER_iv_length(c));
+#endif
+}
+
+/**
+ * RFC 4851 section 5.1 - EAP-FAST Authentication Phase 1: Key Derivations
+ */
+static void eap_fast_init_keys(REQUEST *request, tls_session_t *tls_session)
+{
+       eap_fast_tunnel_t *t = tls_session->opaque;
+       uint8_t *buf;
+       uint8_t *scratch;
+       size_t ksize;
+
+       RDEBUG2("Deriving EAP-FAST keys");
+
+       rad_assert(t->simck == NULL);
+
+       ksize = openssl_get_keyblock_size(request, tls_session->ssl);
+       rad_assert(ksize > 0);
+       buf = talloc_size(request, ksize + sizeof(*t->keyblock));
+       scratch = talloc_size(request, ksize + sizeof(*t->keyblock));
+
+       t->keyblock = talloc(t, eap_fast_keyblock_t);
+
+       eap_fast_tls_gen_challenge(tls_session->ssl, buf, scratch, ksize + sizeof(*t->keyblock), "key expansion");
+       memcpy(t->keyblock, &buf[ksize], sizeof(*t->keyblock));
+       memset(buf, 0, ksize + sizeof(*t->keyblock));
+
+       t->simck = talloc_size(t, EAP_FAST_SIMCK_LEN);
+       memcpy(t->simck, t->keyblock, EAP_FAST_SKS_LEN);        /* S-IMCK[0] = session_key_seed */
+
+       t->cmk = talloc_size(t, EAP_FAST_CMK_LEN);      /* note that CMK[0] is not defined */
+       t->imckc = 0;
+
+       talloc_free(buf);
+       talloc_free(scratch);
+}
+
+/**
+ * RFC 4851 section 5.2 - Intermediate Compound Key Derivations
+ */
+static void eap_fast_update_icmk(REQUEST *request, tls_session_t *tls_session, uint8_t *msk)
+{
+       eap_fast_tunnel_t *t = tls_session->opaque;
+       uint8_t imck[EAP_FAST_SIMCK_LEN + EAP_FAST_CMK_LEN];
+
+       RDEBUG2("Updating ICMK");
+
+       T_PRF(t->simck, EAP_FAST_SIMCK_LEN, "Inner Methods Compound Keys", msk, 32, imck, sizeof(imck));
+
+       memcpy(t->simck, imck, EAP_FAST_SIMCK_LEN);
+       memcpy(t->cmk, &imck[EAP_FAST_SIMCK_LEN], EAP_FAST_CMK_LEN);
+       t->imckc++;
+
+       /*
+         * Calculate MSK/EMSK at the same time as they are coupled to ICMK
+         *
+         * RFC 4851 section 5.4 - EAP Master Session Key Generation
+         */
+       t->msk = talloc_size(t, EAP_FAST_KEY_LEN);
+       T_PRF(t->simck, EAP_FAST_SIMCK_LEN, "Session Key Generating Function", NULL, 0, t->msk, EAP_FAST_KEY_LEN);
+
+       t->emsk = talloc_size(t, EAP_EMSK_LEN);
+       T_PRF(t->simck, EAP_FAST_SIMCK_LEN, "Extended Session Key Generating Function", NULL, 0, t->emsk, EAP_EMSK_LEN);
+}
+
+void eap_fast_tlv_append(tls_session_t *tls_session, int tlv, bool mandatory, int length, const void *data)
+{
+       uint16_t hdr[2];
+
+       hdr[0] = (mandatory) ? htons(tlv | EAP_FAST_TLV_MANDATORY) : htons(tlv);
+       hdr[1] = htons(length);
+
+       tls_session->record_plus(&tls_session->clean_in, &hdr, 4);
+       tls_session->record_plus(&tls_session->clean_in, data, length);
+}
+
+static void eap_fast_send_error(tls_session_t *tls_session, int error)
+{
+       uint32_t value;
+       value = htonl(error);
+
+       eap_fast_tlv_append(tls_session, EAP_FAST_TLV_ERROR, true, sizeof(value), &value);
+}
+
+static void eap_fast_append_result(tls_session_t *tls_session, PW_CODE code)
+{
+       eap_fast_tunnel_t *t = (eap_fast_tunnel_t *) tls_session->opaque;
+
+       int type = (t->result_final)
+                       ? EAP_FAST_TLV_RESULT
+                       : EAP_FAST_TLV_INTERMED_RESULT;
+
+       uint16_t state = (code == PW_CODE_ACCESS_REJECT)
+                       ? EAP_FAST_TLV_RESULT_FAILURE
+                       : EAP_FAST_TLV_RESULT_SUCCESS;
+       state = htons(state);
+
+       eap_fast_tlv_append(tls_session, type, true, sizeof(state), &state);
+}
+
+static void eap_fast_send_identity_request(REQUEST *request, tls_session_t *tls_session, eap_handler_t *eap_session)
+{
+       eap_packet_raw_t eap_packet;
+
+       RDEBUG("Sending EAP-Identity");
+
+       eap_packet.code = PW_EAP_REQUEST;
+       eap_packet.id = eap_session->eap_ds->response->id + 1;
+       eap_packet.length[0] = 0;
+       eap_packet.length[1] = EAP_HEADER_LEN + 1;
+       eap_packet.data[0] = PW_EAP_IDENTITY;
+
+       eap_fast_tlv_append(tls_session, EAP_FAST_TLV_EAP_PAYLOAD, true, sizeof(eap_packet), &eap_packet);
+}
+
+static void eap_fast_send_pac_tunnel(REQUEST *request, tls_session_t *tls_session)
+{
+       eap_fast_tunnel_t                       *t = tls_session->opaque;
+       eap_fast_pac_t                          pac;
+       eap_fast_attr_pac_opaque_plaintext_t    opaque_plaintext;
+       int                                     alen, dlen;
+
+       memset(&pac, 0, sizeof(pac));
+       memset(&opaque_plaintext, 0, sizeof(opaque_plaintext));
+
+       RDEBUG("Sending Tunnel PAC");
+
+       pac.key.hdr.type = htons(EAP_FAST_TLV_MANDATORY | PAC_INFO_PAC_KEY);
+       pac.key.hdr.length = htons(sizeof(pac.key.data));
+       rad_assert(sizeof(pac.key.data) % sizeof(uint32_t) == 0);
+       RANDFILL(pac.key.data);
+
+       pac.info.lifetime.hdr.type = htons(PAC_INFO_PAC_LIFETIME);
+       pac.info.lifetime.hdr.length = htons(sizeof(pac.info.lifetime.data));
+       pac.info.lifetime.data = htonl(time(NULL) + t->pac_lifetime);
+
+       pac.info.a_id.hdr.type = htons(EAP_FAST_TLV_MANDATORY | PAC_INFO_A_ID);
+       pac.info.a_id.hdr.length = htons(sizeof(pac.info.a_id.data));
+       memcpy(pac.info.a_id.data, t->a_id, sizeof(pac.info.a_id.data));
+
+       pac.info.a_id_info.hdr.type = htons(PAC_INFO_A_ID_INFO);
+       pac.info.a_id_info.hdr.length = htons(sizeof(pac.info.a_id_info.data));
+       #define MIN(a,b) (((a)>(b)) ? (b) : (a))
+       alen = MIN(talloc_array_length(t->authority_identity) - 1, sizeof(pac.info.a_id_info.data));
+       memcpy(pac.info.a_id_info.data, t->authority_identity, alen);
+
+       pac.info.type.hdr.type = htons(EAP_FAST_TLV_MANDATORY | PAC_INFO_PAC_TYPE);
+       pac.info.type.hdr.length = htons(sizeof(pac.info.type.data));
+       pac.info.type.data = htons(PAC_TYPE_TUNNEL);
+
+       pac.info.hdr.type = htons(EAP_FAST_TLV_MANDATORY | PAC_INFO_PAC_INFO);
+       pac.info.hdr.length = htons(sizeof(pac.info.lifetime)
+                               + sizeof(pac.info.a_id)
+                               + sizeof(pac.info.a_id_info)
+                               + sizeof(pac.info.type));
+
+       memcpy(&opaque_plaintext.type, &pac.info.type, sizeof(opaque_plaintext.type));
+       memcpy(&opaque_plaintext.lifetime, &pac.info.lifetime, sizeof(opaque_plaintext.lifetime));
+       memcpy(&opaque_plaintext.key, &pac.key, sizeof(opaque_plaintext.key));
+
+
+       rad_assert(PAC_A_ID_LENGTH <= EVP_GCM_TLS_TAG_LEN);
+       memcpy(pac.opaque.aad, t->a_id, PAC_A_ID_LENGTH);
+       rad_assert(RAND_bytes(pac.opaque.iv, sizeof(pac.opaque.iv)) != 0);
+       dlen = eap_fast_encrypt((unsigned const char *)&opaque_plaintext, sizeof(opaque_plaintext),
+                                   t->a_id, PAC_A_ID_LENGTH, t->pac_opaque_key, pac.opaque.iv,
+                                   pac.opaque.data, pac.opaque.tag);
+
+       pac.opaque.hdr.type = htons(EAP_FAST_TLV_MANDATORY | PAC_INFO_PAC_OPAQUE);
+       pac.opaque.hdr.length = htons(sizeof(pac.opaque) - sizeof(pac.opaque.hdr) - sizeof(pac.opaque.data) + dlen);
+
+       eap_fast_tlv_append(tls_session, EAP_FAST_TLV_MANDATORY | EAP_FAST_TLV_PAC, true,
+                           sizeof(pac) - sizeof(pac.opaque.data) + dlen, &pac);
+}
+
+static void eap_fast_append_crypto_binding(REQUEST *request, tls_session_t *tls_session)
+{
+       eap_fast_tunnel_t               *t = tls_session->opaque;
+       eap_tlv_crypto_binding_tlv_t    binding;
+    memset(&binding, 0, sizeof(eap_tlv_crypto_binding_tlv_t));
+       const int                       len = sizeof(binding) - (&binding.reserved - (uint8_t *)&binding);
+
+       RDEBUG("Sending Cryptobinding");
+
+       binding.tlv_type = htons(EAP_FAST_TLV_MANDATORY | EAP_FAST_TLV_CRYPTO_BINDING);
+       binding.length = htons(len);
+       binding.version = EAP_FAST_VERSION;
+       binding.received_version = EAP_FAST_VERSION;    /* FIXME use the clients value */
+       binding.subtype = EAP_FAST_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST;
+
+       rad_assert(sizeof(binding.nonce) % sizeof(uint32_t) == 0);
+       RANDFILL(binding.nonce);
+       binding.nonce[sizeof(binding.nonce) - 1] &= ~0x01; /* RFC 4851 section 4.2.8 */
+
+
+       fr_hmac_sha1(binding.compound_mac, (uint8_t *)&binding, sizeof(binding), t->cmk, EAP_FAST_CMK_LEN);
+
+       eap_fast_tlv_append(tls_session, EAP_FAST_TLV_CRYPTO_BINDING, true, len, &binding.reserved);
+}
+
+static int eap_fast_verify(REQUEST *request, tls_session_t *tls_session, uint8_t const *data, unsigned int data_len)
+{
+       uint16_t attr;
+       uint16_t length;
+       unsigned int remaining = data_len;
+       int     total = 0;
+       int     num[EAP_FAST_TLV_MAX] = {0};
+       eap_fast_tunnel_t *t = (eap_fast_tunnel_t *) tls_session->opaque;
+       uint32_t present = 0;
+
+       rad_assert(sizeof(present) * 8 > EAP_FAST_TLV_MAX);
+
+       while (remaining > 0) {
+               if (remaining < 4) {
+                       RDEBUG2("EAP-FAST TLV is too small (%u) to contain a EAP-FAST TLV header", remaining);
+                       return 0;
+               }
+
+               memcpy(&attr, data, sizeof(attr));
+               attr = ntohs(attr) & EAP_FAST_TLV_TYPE;
+
+               switch (attr) {
+               case EAP_FAST_TLV_RESULT:
+               case EAP_FAST_TLV_NAK:
+               case EAP_FAST_TLV_ERROR:
+               case EAP_FAST_TLV_VENDOR_SPECIFIC:
+               case EAP_FAST_TLV_EAP_PAYLOAD:
+               case EAP_FAST_TLV_INTERMED_RESULT:
+               case EAP_FAST_TLV_PAC:
+               case EAP_FAST_TLV_CRYPTO_BINDING:
+                       num[attr]++;
+                       present |= 1 << attr;
+
+                       if (num[EAP_FAST_TLV_EAP_PAYLOAD] > 1) {
+                               RDEBUG("Too many EAP-Payload TLVs");
+unexpected:
+                               for (int i = 0; i < EAP_FAST_TLV_MAX; i++)
+                                       if (present & (1 << i))
+                                               RDEBUG(" - attribute %d is present", i);
+                               eap_fast_send_error(tls_session, EAP_FAST_ERR_UNEXPECTED_TLV);
+                               return 0;
+                       }
+
+                       if (num[EAP_FAST_TLV_INTERMED_RESULT] > 1) {
+                               RDEBUG("Too many Intermediate-Result TLVs");
+                               goto unexpected;
+                       }
+                       break;
+               default:
+                       if ((data[0] & 0x80) != 0) {
+                               RDEBUG("Unknown mandatory TLV %02x", attr);
+                               goto unexpected;
+                       }
+
+                       num[0]++;
+               }
+
+               total++;
+
+               memcpy(&length, data + 2, sizeof(length));
+               length = ntohs(length);
+
+               data += 4;
+               remaining -= 4;
+
+               if (length > remaining) {
+                       RDEBUG2("EAP-FAST TLV %u is longer than room remaining in the packet (%u > %u).", attr,
+                               length, remaining);
+                       return 0;
+               }
+
+               /*
+                * If the rest of the TLVs are larger than
+                * this attribute, continue.
+                *
+                * Otherwise, if the attribute over-flows the end
+                * of the TLCs, die.
+                */
+               if (remaining < length) {
+                       RDEBUG2("EAP-FAST TLV overflows packet!");
+                       return 0;
+               }
+
+               /*
+                * If there's an error, we bail out of the
+                * authentication process before allocating
+                * memory.
+                */
+               if ((attr == EAP_FAST_TLV_INTERMED_RESULT) || (attr == EAP_FAST_TLV_RESULT)) {
+                       uint16_t status;
+
+                       if (length < 2) {
+                               RDEBUG("EAP-FAST TLV %u is too short.  Expected 2, got %d.", attr, length);
+                               return 0;
+                       }
+
+                       memcpy(&status, data, 2);
+                       status = ntohs(status);
+
+                       if (status == EAP_FAST_TLV_RESULT_FAILURE) {
+                               RDEBUG("EAP-FAST TLV %u indicates failure.  Rejecting request.", attr);
+                               return 0;
+                       }
+
+                       if (status != EAP_FAST_TLV_RESULT_SUCCESS) {
+                               RDEBUG("EAP-FAST TLV %u contains unknown value.  Rejecting request.", attr);
+                               goto unexpected;
+                       }
+               }
+
+               /*
+                * remaining > length, continue.
+                */
+               remaining -= length;
+               data += length;
+       }
+
+       /*
+        * Check if the peer mixed & matched TLVs.
+        */
+       if ((num[EAP_FAST_TLV_NAK] > 0) && (num[EAP_FAST_TLV_NAK] != total)) {
+               RDEBUG("NAK TLV sent with non-NAK TLVs.  Rejecting request.");
+               goto unexpected;
+       }
+
+       if (num[EAP_FAST_TLV_INTERMED_RESULT] > 0 && num[EAP_FAST_TLV_RESULT]) {
+               RDEBUG("NAK TLV sent with non-NAK TLVs.  Rejecting request.");
+               goto unexpected;
+       }
+
+       /*
+        * Check mandatory or not mandatory TLVs.
+        */
+       switch (t->stage) {
+       case TLS_SESSION_HANDSHAKE:
+               if (present) {
+                       RDEBUG("Unexpected TLVs in TLS Session Handshake stage");
+                       goto unexpected;
+               }
+               break;
+       case AUTHENTICATION:
+               if (present != 1 << EAP_FAST_TLV_EAP_PAYLOAD) {
+                       RDEBUG("Unexpected TLVs in authentication stage");
+                       goto unexpected;
+               }
+               break;
+       case CRYPTOBIND_CHECK:
+       {
+               uint32_t bits = (t->result_final)
+                               ? 1 << EAP_FAST_TLV_RESULT
+                               : 1 << EAP_FAST_TLV_INTERMED_RESULT;
+               if (present & ~(bits | (1 << EAP_FAST_TLV_CRYPTO_BINDING) | (1 << EAP_FAST_TLV_PAC))) {
+                       RDEBUG("Unexpected TLVs in cryptobind checking stage");
+                       goto unexpected;
+               }
+               break;
+       }
+       case PROVISIONING:
+               if (present & ~((1 << EAP_FAST_TLV_PAC) | (1 << EAP_FAST_TLV_RESULT))) {
+                       RDEBUG("Unexpected TLVs in provisioning stage");
+                       goto unexpected;
+               }
+               break;
+       case COMPLETE:
+               if (present) {
+                       RDEBUG("Unexpected TLVs in complete stage");
+                       goto unexpected;
+               }
+               break;
+       default:
+               RDEBUG("Unexpected stage %d", t->stage);
+               return 0;
+       }
+
+       /*
+        * We got this far.  It looks OK.
+        */
+       return 1;
+}
+
+static ssize_t eap_fast_decode_vp(TALLOC_CTX *request, DICT_ATTR const *parent,
+                                   uint8_t const *data, size_t const attr_len, VALUE_PAIR **out)
+{
+       int8_t                  tag = TAG_NONE;
+       VALUE_PAIR              *vp;
+       uint8_t const           *p = data;
+
+       /*
+        *      FIXME: Attrlen can be larger than 253 for extended attrs!
+        */
+       if (!parent || !out ) {
+               RERROR("eap_fast_decode_vp: Invalid arguments");
+               return -1;
+       }
+
+       /*
+        *      Silently ignore zero-length attributes.
+        */
+       if (attr_len == 0) return 0;
+
+       /*
+        *      And now that we've verified the basic type
+        *      information, decode the actual p.
+        */
+       vp = fr_pair_afrom_da(request, parent);
+       if (!vp) return -1;
+
+       vp->vp_length = attr_len;
+       vp->tag = tag;
+
+       switch (parent->type) {
+       case PW_TYPE_STRING:
+               fr_pair_value_bstrncpy(vp, p, attr_len);
+               break;
+
+       case PW_TYPE_OCTETS:
+               fr_pair_value_memcpy(vp, p, attr_len);
+               break;
+
+       case PW_TYPE_ABINARY:
+               if (vp->vp_length > sizeof(vp->vp_filter)) {
+                       vp->vp_length = sizeof(vp->vp_filter);
+               }
+               memcpy(vp->vp_filter, p, vp->vp_length);
+               break;
+
+       case PW_TYPE_BYTE:
+               vp->vp_byte = p[0];
+               break;
+
+       case PW_TYPE_SHORT:
+               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);
+               break;
+
+       case PW_TYPE_INTEGER64:
+               memcpy(&vp->vp_integer64, p, 8);
+               vp->vp_integer64 = ntohll(vp->vp_integer64);
+               break;
+
+       case PW_TYPE_DATE:
+               memcpy(&vp->vp_date, p, 4);
+               vp->vp_date = ntohl(vp->vp_date);
+               break;
+
+       case PW_TYPE_ETHERNET:
+               memcpy(vp->vp_ether, p, 6);
+               break;
+
+       case PW_TYPE_IPV4_ADDR:
+               memcpy(&vp->vp_ipaddr, p, 4);
+               break;
+
+       case PW_TYPE_IFID:
+               memcpy(vp->vp_ifid, p, 8);
+               break;
+
+       case PW_TYPE_IPV6_ADDR:
+               memcpy(&vp->vp_ipv6addr, p, 16);
+               break;
+
+       case PW_TYPE_IPV6_PREFIX:
+               /*
+                *      FIXME: double-check that
+                *      (vp->vp_octets[1] >> 3) matches vp->vp_length + 2
+                */
+               memcpy(vp->vp_ipv6prefix, p, vp->vp_length);
+               if (vp->vp_length < 18) {
+                       memset(((uint8_t *)vp->vp_ipv6prefix) + vp->vp_length, 0,
+                              18 - vp->vp_length);
+               }
+               break;
+
+       case PW_TYPE_IPV4_PREFIX:
+               /* FIXME: do the same double-check as for IPv6Prefix */
+               memcpy(vp->vp_ipv4prefix, p, vp->vp_length);
+
+               /*
+                *      /32 means "keep all bits".  Otherwise, mask
+                *      them out.
+                */
+               if ((p[1] & 0x3f) > 32) {
+                       uint32_t addr, mask;
+
+                       memcpy(&addr, vp->vp_octets + 2, sizeof(addr));
+                       mask = 1;
+                       mask <<= (32 - (p[1] & 0x3f));
+                       mask--;
+                       mask = ~mask;
+                       mask = htonl(mask);
+                       addr &= mask;
+                       memcpy(vp->vp_ipv4prefix + 2, &addr, sizeof(addr));
+               }
+               break;
+
+       case PW_TYPE_SIGNED:    /* overloaded with vp_integer */
+               memcpy(&vp->vp_integer, p, 4);
+               vp->vp_integer = ntohl(vp->vp_integer);
+               break;
+
+       default:
+               RERROR("eap_fast_decode_vp: type %d Internal sanity check  %d ", parent->type, __LINE__);
+               fr_pair_list_free(&vp);
+               return -1;
+       }
+       vp->type = VT_DATA;
+    *out = vp;
+       return attr_len;
+}
+
+
+VALUE_PAIR *eap_fast_fast2vp(REQUEST *request, SSL *ssl, uint8_t const *data, size_t data_len,
+                             DICT_ATTR const *fast_da, vp_cursor_t *out)
+{
+       uint16_t        attr;
+       uint16_t        length;
+       size_t          data_left = data_len;
+       VALUE_PAIR      *first = NULL;
+       VALUE_PAIR      *vp = NULL;
+       DICT_ATTR const *da;
+
+       if (!fast_da)
+               fast_da = dict_attrbyvalue(PW_FREERADIUS_EAP_FAST_TLV, VENDORPEC_FREERADIUS);
+       rad_assert(fast_da != NULL);
+
+       if (!out) {
+               out = talloc(request, vp_cursor_t);
+               rad_assert(out != NULL);
+               fr_cursor_init(out, &first);
+       }
+
+       /*
+        * Decode the TLVs
+        */
+       while (data_left > 0) {
+               ssize_t decoded;
+
+               /* FIXME do something with mandatory */
+
+               memcpy(&attr, data, sizeof(attr));
+               attr = ntohs(attr) & EAP_FAST_TLV_TYPE;
+
+               memcpy(&length, data + 2, sizeof(length));
+               length = ntohs(length);
+
+               data += 4;
+               data_left -= 4;
+
+               /*
+                * Look up the TLV.
+                *
+                * For now, if it doesn't exist, ignore it.
+                */
+               da = dict_attrbyparent(fast_da, attr, fast_da->vendor);
+               if (!da) {
+                       RDEBUG("eap_fast_fast2vp: no sub attribute found %s attr: %u vendor: %u",
+                                       fast_da->name, attr, fast_da->vendor);
+                       goto next_attr;
+               }
+               if (da->type == PW_TYPE_TLV) {
+                       eap_fast_fast2vp(request, ssl, data, length, da, out);
+                       goto next_attr;
+               }
+               decoded = eap_fast_decode_vp(request, da, data, length, &vp);
+               if (decoded < 0) {
+                       RERROR("Failed decoding %s: %s", da->name, fr_strerror());
+                       goto next_attr;
+               }
+
+               fr_cursor_merge(out, vp);
+
+       next_attr:
+               while (fr_cursor_next(out)) {
+                       /* nothing */
+               }
+
+               data += length;
+               data_left -= length;
+       }
+
+       /*
+        * We got this far.  It looks OK.
+        */
+       return first;
+}
+
+
+static void eapfast_copy_request_to_tunnel(REQUEST *request, REQUEST *fake) {
+    VALUE_PAIR *copy, *vp;
+    vp_cursor_t 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.
+         */
+        if ((vp->da->attr > 255) && (((vp->da->attr >> 16) & 0xffff) == 0)) {
+            continue;
+        }
+
+        /*
+         *     The outside attribute is already in the
+         *     tunnel, don't copy it.
+         *
+         *     This works for BOTH attributes which
+         *     are originally in the tunneled request,
+         *     AND attributes which are copied there
+         *     from below.
+         */
+        if (fr_pair_find_by_da(fake->packet->vps, vp->da, TAG_ANY)) continue;
+
+        /*
+         *     Some attributes are handled specially.
+         */
+        if (!vp->da->vendor) switch (vp->da->attr) {
+            /*
+             * NEVER copy Message-Authenticator,
+             * EAP-Message, or State.  They're
+             * only for outside of the tunnel.
+             */
+        case PW_USER_NAME:
+        case PW_USER_PASSWORD:
+        case PW_CHAP_PASSWORD:
+        case PW_CHAP_CHALLENGE:
+        case PW_PROXY_STATE:
+        case PW_MESSAGE_AUTHENTICATOR:
+        case PW_EAP_MESSAGE:
+        case PW_STATE:
+            continue;
+
+            /*
+             * By default, copy it over.
+             */
+        default:
+            break;
+        }
+
+        /*
+         *     Don't copy from the head, we've already
+         *     checked it.
+         */
+        copy = fr_pair_list_copy_by_num(fake->packet, vp, vp->da->attr, vp->da->vendor, TAG_ANY);
+        fr_pair_add(&fake->packet->vps, copy);
+    }
+}
+
+/*
+ * Use a reply packet to determine what to do.
+ */
+static rlm_rcode_t CC_HINT(nonnull) process_reply( eap_handler_t *eap_session,
+                                                 tls_session_t *tls_session,
+                                                 REQUEST *request, RADIUS_PACKET *reply)
+{
+       rlm_rcode_t                     rcode = RLM_MODULE_REJECT;
+       VALUE_PAIR                      *vp;
+       vp_cursor_t                     cursor;
+
+       eap_fast_tunnel_t       *t = tls_session->opaque;
+
+       rad_assert(eap_session->request == request);
+
+       /*
+        * If the response packet was Access-Accept, then
+        * we're OK.  If not, die horribly.
+        *
+        * FIXME: EAP-Messages can only start with 'identity',
+        * NOT 'eap start', so we should check for that....
+        */
+       switch (reply->code) {
+       case PW_CODE_ACCESS_ACCEPT:
+               RDEBUG("Got tunneled Access-Accept");
+               rcode = RLM_MODULE_OK;
+
+               for (vp = fr_cursor_init(&cursor, &reply->vps); vp; vp = fr_cursor_next(&cursor)) {
+                       if (vp->da->vendor != VENDORPEC_MICROSOFT) continue;
+
+                       /* FIXME must be a better way to capture/re-derive this later for ISK */
+                       switch (vp->da->attr) {
+                       case PW_MSCHAP_MPPE_SEND_KEY:
+                               memcpy(t->isk.mppe_send, vp->vp_octets, CHAP_VALUE_LENGTH);
+                               break;
+
+                       case PW_MSCHAP_MPPE_RECV_KEY:
+                               memcpy(t->isk.mppe_recv, vp->vp_octets, CHAP_VALUE_LENGTH);
+                               break;
+
+                       case PW_MSCHAP2_SUCCESS:
+                               RDEBUG("Got %s, tunneling it to the client in a challenge", vp->da->name);
+                               rcode = RLM_MODULE_HANDLED;
+                               if (t->use_tunneled_reply) {
+                                       t->authenticated = true;
+                                       /*
+                                        *      Clean up the tunneled reply.
+                                        */
+                                       fr_pair_delete_by_num(&reply->vps, PW_PROXY_STATE, 0, TAG_ANY);
+                                       fr_pair_delete_by_num(&reply->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
+                                       fr_pair_delete_by_num(&reply->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY);
+
+                                       /*
+                                        *      Delete MPPE keys & encryption policy.  We don't
+                                        *      want these here.
+                                        */
+                                       fr_pair_delete_by_num(&reply->vps, 7, VENDORPEC_MICROSOFT, TAG_ANY);
+                                       fr_pair_delete_by_num(&reply->vps, 8, VENDORPEC_MICROSOFT, TAG_ANY);
+                                       fr_pair_delete_by_num(&reply->vps, 16, VENDORPEC_MICROSOFT, TAG_ANY);
+                                       fr_pair_delete_by_num(&reply->vps, 17, VENDORPEC_MICROSOFT, TAG_ANY);
+
+                                       fr_pair_list_free(&t->accept_vps); /* for proxying MS-CHAP2 */
+                                       fr_pair_list_mcopy_by_num(t, &t->accept_vps, &reply->vps, 0, 0, TAG_ANY);
+                                       rad_assert(!reply->vps);
+                               }
+                               break;
+                               
+                       default:
+                               break;
+                       }
+               }
+               break;
+
+       case PW_CODE_ACCESS_REJECT:
+               RDEBUG("Got tunneled Access-Reject");
+               rcode = RLM_MODULE_REJECT;
+               break;
+
+       /*
+        * Handle Access-Challenge, but only if we
+        * send tunneled reply data.  This is because
+        * an Access-Challenge means that we MUST tunnel
+        * a Reply-Message to the client.
+        */
+       case PW_CODE_ACCESS_CHALLENGE:
+               RDEBUG("Got tunneled Access-Challenge");
+
+               /*
+                *      Keep the State attribute, if necessary.
+                *
+                *      Get rid of the old State, too.
+                */
+               fr_pair_list_free(&t->state);
+               fr_pair_list_mcopy_by_num(t, &t->state, &reply->vps, PW_STATE, 0, TAG_ANY);
+
+               /*
+                *      Copy the EAP-Message back to the tunnel.
+                */
+               (void) fr_cursor_init(&cursor, &reply->vps);
+
+               while ((vp = fr_cursor_next_by_num(&cursor, PW_EAP_MESSAGE, 0, TAG_ANY)) != NULL) {
+                       eap_fast_tlv_append(tls_session, EAP_FAST_TLV_EAP_PAYLOAD, true, vp->vp_length, vp->vp_octets);
+               }
+
+               rcode = RLM_MODULE_HANDLED;
+               break;
+
+       default:
+               RDEBUG("Unknown RADIUS packet type %d: rejecting tunneled user", reply->code);
+               rcode = RLM_MODULE_INVALID;
+               break;
+       }
+
+
+       return rcode;
+}
+
+static PW_CODE eap_fast_eap_payload(REQUEST *request, eap_handler_t *eap_session,
+                                   tls_session_t *tls_session, VALUE_PAIR *tlv_eap_payload)
+{
+       PW_CODE                 code = PW_CODE_ACCESS_REJECT;
+       rlm_rcode_t             rcode;
+       VALUE_PAIR              *vp;
+       eap_fast_tunnel_t       *t;
+       REQUEST                 *fake;
+
+       RDEBUG("Processing received EAP Payload");
+
+       /*
+        * Allocate a fake REQUEST structure.
+        */
+       fake = request_alloc_fake(request);
+       rad_assert(!fake->packet->vps);
+
+       t = (eap_fast_tunnel_t *) tls_session->opaque;
+
+       /*
+        * Add the tunneled attributes to the fake request.
+        */
+
+       fake->packet->vps = fr_pair_afrom_num(fake->packet, PW_EAP_MESSAGE, 0);
+       fr_pair_value_memcpy(fake->packet->vps, tlv_eap_payload->vp_octets, tlv_eap_payload->vp_length);
+
+       RDEBUG("Got tunneled request");
+       rdebug_pair_list(L_DBG_LVL_1, request, fake->packet->vps, NULL);
+
+       /*
+        * Tell the request that it's a fake one.
+        */
+       fr_pair_make(fake->packet, &fake->packet->vps, "Freeradius-Proxied-To", "127.0.0.1", T_OP_EQ);
+
+       /*
+        * Update other items in the REQUEST data structure.
+        */
+       fake->username = fr_pair_find_by_num(fake->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+       fake->password = fr_pair_find_by_num(fake->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
+
+       /*
+        * No User-Name, try to create one from stored data.
+        */
+       if (!fake->username) {
+               /*
+                * No User-Name in the stored data, look for
+                * an EAP-Identity, and pull it out of there.
+                */
+               if (!t->username) {
+                       vp = fr_pair_find_by_num(fake->packet->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
+                       if (vp &&
+                           (vp->vp_length >= EAP_HEADER_LEN + 2) &&
+                           (vp->vp_strvalue[0] == PW_EAP_RESPONSE) &&
+                           (vp->vp_strvalue[EAP_HEADER_LEN] == PW_EAP_IDENTITY) &&
+                           (vp->vp_strvalue[EAP_HEADER_LEN + 1] != 0)) {
+                               /*
+                                * Create & remember a User-Name
+                                */
+                               t->username = fr_pair_make(t, NULL, "User-Name", NULL, T_OP_EQ);
+                               rad_assert(t->username != NULL);
+
+                               fr_pair_value_bstrncpy(t->username, vp->vp_octets + 5, vp->vp_length - 5);
+
+                               RDEBUG("Got tunneled identity of %s", t->username->vp_strvalue);
+                       } else {
+                               /*
+                                * Don't reject the request outright,
+                                * as it's permitted to do EAP without
+                                * user-name.
+                                */
+                               RWDEBUG2("No EAP-Identity found to start EAP conversation");
+                       }
+               } /* else there WAS a t->username */
+
+               if (t->username) {
+                       vp = fr_pair_list_copy(fake->packet, t->username);
+                       fr_pair_add(&fake->packet->vps, vp);
+                       fake->username = vp;
+               }
+       } /* else the request ALREADY had a User-Name */
+
+       /*
+        *      Add the State attribute, too, if it exists.
+        */
+       if (t->state) {
+               vp = fr_pair_list_copy(fake->packet, t->state);
+               if (vp) fr_pair_add(&fake->packet->vps, vp);
+       }
+
+
+       if (t->stage == AUTHENTICATION) {       /* FIXME do this only for MSCHAPv2 */
+               VALUE_PAIR *tvp;
+
+        RWDEBUG2("AUTHENTICATION");
+        vp = fr_pair_make(fake, &fake->config, "EAP-Type", "0", T_OP_EQ);
+        vp->vp_integer = t->default_method;
+        RWDEBUG2("AUTHENTICATION");
+
+               /*
+                * RFC 5422 section 3.2.3 - Authenticating Using EAP-FAST-MSCHAPv2
+                */
+               if (t->mode == EAP_FAST_PROVISIONING_ANON) {
+                       tvp = fr_pair_afrom_num(fake, PW_MSCHAP_CHALLENGE, VENDORPEC_MICROSOFT);
+                       fr_pair_value_memcpy(tvp, t->keyblock->server_challenge, CHAP_VALUE_LENGTH);
+                       fr_pair_add(&fake->config, tvp);
+
+                       tvp = fr_pair_afrom_num(fake, PW_MS_CHAP_PEER_CHALLENGE, 0);
+                       fr_pair_value_memcpy(tvp, t->keyblock->client_challenge, CHAP_VALUE_LENGTH);
+                       fr_pair_add(&fake->config, tvp);
+               }
+       }
+
+       if (t->copy_request_to_tunnel) {
+               eapfast_copy_request_to_tunnel(request, fake);
+       }
+
+       if ((vp = fr_pair_find_by_num(request->config, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) {
+               fake->server = vp->vp_strvalue;
+
+       } else if (t->virtual_server) {
+               fake->server = t->virtual_server;
+
+       } /* else fake->server == request->server */
+
+       /*
+        * Call authentication recursively, which will
+        * do PAP, CHAP, MS-CHAP, etc.
+        */
+       rad_virtual_server(fake);
+
+       /*
+        * Decide what to do with the reply.
+        */
+       switch (fake->reply->code) {
+       case 0:
+               RDEBUG("No tunneled reply was found, rejecting the user.");
+               code = PW_CODE_ACCESS_REJECT;
+               break;
+
+       default:
+               /*
+                * Returns RLM_MODULE_FOO, and we want to return PW_FOO
+                */
+               rcode = process_reply(eap_session, tls_session, request, fake->reply);
+               switch (rcode) {
+               case RLM_MODULE_REJECT:
+                       code = PW_CODE_ACCESS_REJECT;
+                       break;
+
+               case RLM_MODULE_HANDLED:
+                       code = PW_CODE_ACCESS_CHALLENGE;
+                       break;
+
+               case RLM_MODULE_OK:
+                       code = PW_CODE_ACCESS_ACCEPT;
+                       break;
+
+               default:
+                       code = PW_CODE_ACCESS_REJECT;
+                       break;
+               }
+               break;
+       }
+
+       talloc_free(fake);
+
+       return code;
+}
+
+static PW_CODE eap_fast_crypto_binding(REQUEST *request, UNUSED eap_handler_t *eap_session,
+                                      tls_session_t *tls_session, eap_tlv_crypto_binding_tlv_t *binding)
+{
+       uint8_t                 cmac[sizeof(binding->compound_mac)];
+       eap_fast_tunnel_t       *t = tls_session->opaque;
+
+       memcpy(cmac, binding->compound_mac, sizeof(cmac));
+       memset(binding->compound_mac, 0, sizeof(binding->compound_mac));
+
+
+       fr_hmac_sha1(binding->compound_mac, (uint8_t *)binding, sizeof(*binding), t->cmk, EAP_FAST_CMK_LEN);
+       if (memcmp(binding->compound_mac, cmac, sizeof(cmac))) {
+               RDEBUG2("Crypto-Binding TLV mis-match");
+               return PW_CODE_ACCESS_REJECT;
+       }
+
+       return PW_CODE_ACCESS_ACCEPT;
+}
+
+
+#define PW_EAP_FAST_TLV_PAC (PW_FREERADIUS_EAP_FAST_TLV | (EAP_FAST_TLV_PAC << 8))
+
+
+
+static PW_CODE eap_fast_process_tlvs(REQUEST *request, eap_handler_t *eap_session,
+                                    tls_session_t *tls_session, VALUE_PAIR *fast_vps)
+{
+       eap_fast_tunnel_t               *t = (eap_fast_tunnel_t *) tls_session->opaque;
+       VALUE_PAIR                      *vp;
+       vp_cursor_t                     cursor;
+       eap_tlv_crypto_binding_tlv_t    *binding = NULL;
+
+       for (vp = fr_cursor_init(&cursor, &fast_vps); vp; vp = fr_cursor_next(&cursor)) {
+               PW_CODE code = PW_CODE_ACCESS_REJECT;
+               char *value;
+               DICT_ATTR const *parent_da = NULL;
+               parent_da = dict_parent(vp->da->attr, vp->da->vendor);
+               if (parent_da == NULL || vp->da->vendor != VENDORPEC_FREERADIUS ||
+                       ((vp->da->attr & 0xff) != PW_FREERADIUS_EAP_FAST_TLV)) {
+                       value = vp_aprints(request->packet, vp, '"');
+                       RDEBUG2("ignoring non-EAP-FAST TLV %s", value);
+                       talloc_free(value);
+                       continue;
+               }
+
+               switch (parent_da->attr) {
+               case PW_FREERADIUS_EAP_FAST_TLV:
+                       switch (vp->da->attr >> 8) {
+                       case EAP_FAST_TLV_EAP_PAYLOAD:
+                               code = eap_fast_eap_payload(request, eap_session, tls_session, vp);
+                               if (code == PW_CODE_ACCESS_ACCEPT)
+                                       t->stage = CRYPTOBIND_CHECK;
+                               break;
+                       case EAP_FAST_TLV_RESULT:
+                       case EAP_FAST_TLV_INTERMED_RESULT:
+                               code = PW_CODE_ACCESS_ACCEPT;
+                               t->stage = PROVISIONING;
+                               break;
+                       case EAP_FAST_TLV_CRYPTO_BINDING:
+                               if (!binding) {
+                                       binding = talloc_zero(request->packet, eap_tlv_crypto_binding_tlv_t);
+                                       memcpy(binding, vp->vp_octets, sizeof(*binding));
+                                       binding->tlv_type = htons(EAP_FAST_TLV_MANDATORY | EAP_FAST_TLV_CRYPTO_BINDING);
+                                       binding->length = htons(sizeof(*binding) - 2 * sizeof(uint16_t));
+                               }
+                               continue;
+                       default:
+                               value = vp_aprints_value(request->packet, vp, '"');
+                               RDEBUG2("ignoring unknown %s", value);
+                               talloc_free(value);
+                               continue;
+                       }
+                       break;
+               case PW_EAP_FAST_TLV_PAC:
+                       switch ( ( vp->da->attr >> 16 )) {
+                       case PAC_INFO_PAC_ACK:
+                               if (vp->vp_integer == EAP_FAST_TLV_RESULT_SUCCESS) {
+                                       code = PW_CODE_ACCESS_ACCEPT;
+                                       t->pac.expires = UINT32_MAX;
+                                       t->pac.expired = false;
+                                       t->stage = COMPLETE;
+                               }
+                               break;
+                       case PAC_INFO_PAC_TYPE:
+                               if (vp->vp_integer != PAC_TYPE_TUNNEL) {
+                                       RDEBUG("only able to serve Tunnel PAC's, ignoring request");
+                                       continue;
+                               }
+                               t->pac.send = true;
+                               continue;
+                       default:
+                               value = vp_aprints(request->packet, vp, '"');
+                               RDEBUG2("ignoring unknown EAP-FAST-PAC-TLV %s", value);
+                               talloc_free(value);
+                               continue;
+                       }
+                       break;
+               default:
+                       value = vp_aprints(request->packet, vp, '"');
+                       RDEBUG2("ignoring EAP-FAST TLV %s", value);
+                       talloc_free(value);
+                       continue;
+               }
+
+               if (code == PW_CODE_ACCESS_REJECT)
+                       return PW_CODE_ACCESS_REJECT;
+       }
+
+       if (binding) {
+               PW_CODE code = eap_fast_crypto_binding(request, eap_session, tls_session, binding);
+               if (code == PW_CODE_ACCESS_ACCEPT)
+                       t->stage = PROVISIONING;
+       }
+
+       return PW_CODE_ACCESS_ACCEPT;
+}
+
+
+/*
+ * Process the inner tunnel data
+ */
+PW_CODE eap_fast_process(eap_handler_t *eap_session, tls_session_t *tls_session)
+{
+       PW_CODE                 code;
+       VALUE_PAIR              *fast_vps;
+       uint8_t                 const *data;
+       size_t                  data_len;
+       eap_fast_tunnel_t               *t;
+       REQUEST                 *request = eap_session->request;
+
+       /*
+        * Just look at the buffer directly, without doing
+        * record_to_buff.
+        */
+       data_len = tls_session->clean_out.used;
+       tls_session->clean_out.used = 0;
+       data = tls_session->clean_out.data;
+
+       t = (eap_fast_tunnel_t *) tls_session->opaque;
+
+       /*
+        * See if the tunneled data is well formed.
+        */
+       if (!eap_fast_verify(request, tls_session, data, data_len)) return PW_CODE_ACCESS_REJECT;
+
+       if (t->stage == TLS_SESSION_HANDSHAKE) {
+               rad_assert(t->mode == EAP_FAST_UNKNOWN);
+
+               char buf[256];
+               if (strstr(SSL_CIPHER_description(SSL_get_current_cipher(tls_session->ssl),
+                                                 buf, sizeof(buf)), "Au=None")) {
+                       /* FIXME enforce MSCHAPv2 - RFC 5422 section 3.2.2 */
+                       RDEBUG2("Using anonymous provisioning");
+                       t->mode = EAP_FAST_PROVISIONING_ANON;
+                       t->pac.send = true;
+               } else {
+                       if (SSL_session_reused(tls_session->ssl)) {
+                               RDEBUG("Session Resumed from PAC");
+                               t->mode = EAP_FAST_NORMAL_AUTH;
+                       } else {
+                               RDEBUG2("Using authenticated provisioning");
+                               t->mode = EAP_FAST_PROVISIONING_AUTH;
+                       }
+
+                       if (!t->pac.expires || t->pac.expired || t->pac.expires - time(NULL) < t->pac_lifetime * 0.6)
+                               t->pac.send = true;
+               }
+
+               eap_fast_init_keys(request, tls_session);
+
+               eap_fast_send_identity_request(request, tls_session, eap_session);
+
+               t->stage = AUTHENTICATION;
+               return PW_CODE_ACCESS_CHALLENGE;
+       }
+
+       fast_vps = eap_fast_fast2vp(request, tls_session->ssl, data, data_len, NULL, NULL);
+
+       RDEBUG("Got Tunneled FAST TLVs");
+       rdebug_pair_list(L_DBG_LVL_1, request, fast_vps, NULL);
+
+       code = eap_fast_process_tlvs(request, eap_session, tls_session, fast_vps);
+
+       fr_pair_list_free(&fast_vps);
+
+       if (code == PW_CODE_ACCESS_REJECT) return PW_CODE_ACCESS_REJECT;
+
+       switch (t->stage) {
+       case AUTHENTICATION:
+               code = PW_CODE_ACCESS_CHALLENGE;
+               break;
+       case CRYPTOBIND_CHECK:
+       {
+               if (t->mode != EAP_FAST_PROVISIONING_ANON && !t->pac.send)
+                       t->result_final = true;
+
+               eap_fast_append_result(tls_session, code);
+
+               eap_fast_update_icmk(request, tls_session, (uint8_t *)&t->isk);
+               eap_fast_append_crypto_binding(request, tls_session);
+
+               code = PW_CODE_ACCESS_CHALLENGE;
+               break;
+       }
+       case PROVISIONING:
+               t->result_final = true;
+
+               eap_fast_append_result(tls_session, code);
+
+               if (code == PW_CODE_ACCESS_REJECT)
+                       break;
+
+               if (t->pac.send) {
+                       RDEBUG("Peer requires new PAC");
+                       eap_fast_send_pac_tunnel(request, tls_session);
+                       code = PW_CODE_ACCESS_CHALLENGE;
+                       break;
+               }
+
+               t->stage = COMPLETE;
+               /* fallthrough */
+       case COMPLETE:
+               /*
+                * RFC 5422 section 3.5 - Network Access after EAP-FAST Provisioning
+                */
+               if (t->pac.type && t->pac.expired) {
+                       REDEBUG("Rejecting expired PAC.");
+                       code = PW_CODE_ACCESS_REJECT;
+                       break;
+               }
+
+               if (t->mode == EAP_FAST_PROVISIONING_ANON) {
+                       REDEBUG("Rejecting unauthenticated provisioning");
+                       code = PW_CODE_ACCESS_REJECT;
+                       break;
+               }
+
+               /*
+                * eap_tls_gen_mppe_keys() is unsuitable for EAP-FAST as Cisco decided
+                * it would be a great idea to flip the recv/send keys around
+                */
+               #define EAPTLS_MPPE_KEY_LEN 32
+               eap_add_reply(request, "MS-MPPE-Recv-Key", t->msk, EAPTLS_MPPE_KEY_LEN);
+               eap_add_reply(request, "MS-MPPE-Send-Key", &t->msk[EAPTLS_MPPE_KEY_LEN], EAPTLS_MPPE_KEY_LEN);
+               eap_add_reply(request, "EAP-MSK", t->msk, EAP_FAST_KEY_LEN);
+               eap_add_reply(request, "EAP-EMSK", t->emsk, EAP_EMSK_LEN);
+
+               break;
+
+       default:
+               RERROR("Internal sanity check failed in EAP-FAST at %d", t->stage);
+               code = PW_CODE_ACCESS_REJECT;
+       }
+
+       return code;
+}
diff --git a/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.h b/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.h
new file mode 100644 (file)
index 0000000..8a88bd6
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * eap_fast.h
+ *
+ * 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 2003 Alan DeKok <aland@freeradius.org>
+ * Copyright 2006 The FreeRADIUS server project
+ */
+#ifndef _EAP_FAST_H
+#define _EAP_FAST_H
+
+RCSIDH(eap_fast_h, "$Id$")
+
+#include "eap_tls.h"
+
+#define EAP_FAST_VERSION                       1
+
+#define EAP_FAST_KEY_LEN                       64
+#define EAP_EMSK_LEN                           64
+#define EAP_FAST_SKS_LEN                       40
+#define EAP_FAST_SIMCK_LEN                     40
+#define EAP_FAST_CMK_LEN                       20
+
+#define EAP_FAST_TLV_MANDATORY                 0x8000
+#define EAP_FAST_TLV_TYPE                      0x3fff
+
+#define EAP_FAST_FATAL_ERROR                   2000
+#define EAP_FAST_ERR_TUNNEL_COMPROMISED                2001
+#define EAP_FAST_ERR_UNEXPECTED_TLV            2002
+
+#define EAP_FAST_TLV_RESULT_SUCCESS            1
+#define EAP_FAST_TLV_RESULT_FAILURE            2
+
+typedef enum eap_fast_stage_t {
+       TLS_SESSION_HANDSHAKE = 0,
+       AUTHENTICATION,
+       CRYPTOBIND_CHECK,
+       PROVISIONING,
+       COMPLETE
+} eap_fast_stage_t;
+
+typedef enum eap_fast_auth_type {
+       EAP_FAST_UNKNOWN = 0,
+       EAP_FAST_PROVISIONING_ANON,
+       EAP_FAST_PROVISIONING_AUTH,
+       EAP_FAST_NORMAL_AUTH
+} eap_fast_auth_type_t;
+
+typedef enum eap_fast_pac_info_attr_type_t {
+       PAC_INFO_PAC_KEY = 1,   // 1
+       PAC_INFO_PAC_OPAQUE,    // 2
+       PAC_INFO_PAC_LIFETIME,  // 3
+       PAC_INFO_A_ID,          // 4
+       PAC_INFO_I_ID,          // 5
+       PAC_INFO_PAC_RESERVED6, // 6
+       PAC_INFO_A_ID_INFO,     // 7
+       PAC_INFO_PAC_ACK,       // 8
+       PAC_INFO_PAC_INFO,      // 9
+       PAC_INFO_PAC_TYPE,      // 10
+       PAC_INFO_MAX
+} eap_fast_pac_info_attr_type_t;
+
+typedef enum eap_fast_pac_type_t {
+       PAC_TYPE_TUNNEL = 1,    // 1
+       PAC_TYPE_MACHINE_AUTH,  // 2
+       PAC_TYPE_USER_AUTHZ,    // 3
+       PAC_TYPE_MAX
+} eap_fast_pac_type_t;
+
+#define PAC_KEY_LENGTH         32
+#define PAC_A_ID_LENGTH                16
+#define PAC_I_ID_LENGTH                16
+#define PAC_A_ID_INFO_LENGTH   32
+
+typedef struct eap_fast_pac_attr_hdr_t {
+       uint16_t                        type;
+       uint16_t                        length;
+} CC_HINT(__packed__) eap_fast_pac_attr_hdr_t;
+
+typedef struct eap_fast_pac_attr_lifetime_t {
+       eap_fast_pac_attr_hdr_t         hdr;
+       uint32_t                        data;   // secs since epoch
+} CC_HINT(__packed__) eap_fast_pac_attr_lifetime_t;
+
+typedef struct eap_fast_pac_attr_a_id_t {
+       eap_fast_pac_attr_hdr_t         hdr;
+       uint8_t                         data[PAC_A_ID_LENGTH];
+} CC_HINT(__packed__) eap_fast_pac_attr_a_id_t;
+
+typedef struct eap_fast_pac_attr_i_id_t {
+       eap_fast_pac_attr_hdr_t         hdr;
+       uint8_t                         data[PAC_I_ID_LENGTH];
+} CC_HINT(__packed__) eap_fast_pac_attr_i_id_t;
+
+typedef struct eap_fast_pac_attr_a_id_info_t {
+       eap_fast_pac_attr_hdr_t         hdr;
+       uint8_t                         data[PAC_A_ID_INFO_LENGTH];
+} CC_HINT(__packed__) eap_fast_pac_attr_a_id_info_t;
+
+typedef struct eap_fast_pac_attr_pac_type_t {
+       eap_fast_pac_attr_hdr_t         hdr;
+       uint16_t                        data;
+} CC_HINT(__packed__) eap_fast_pac_attr_pac_type_t;
+
+typedef struct eap_fast_pac_attr_pac_key_t {
+       eap_fast_pac_attr_hdr_t         hdr;
+       uint8_t                         data[PAC_KEY_LENGTH];
+} CC_HINT(__packed__) eap_fast_pac_attr_pac_key_t;
+
+typedef struct eap_fast_attr_pac_opaque_plaintext_t {
+       eap_fast_pac_attr_pac_type_t    type;
+       eap_fast_pac_attr_lifetime_t    lifetime;
+       eap_fast_pac_attr_pac_key_t     key;
+} CC_HINT(__packed__) eap_fast_attr_pac_opaque_plaintext_t;
+
+typedef struct eap_fast_attr_pac_opaque_t {
+       eap_fast_pac_attr_hdr_t         hdr;
+       unsigned char                   aad[PAC_A_ID_LENGTH];
+       unsigned char                   iv[EVP_MAX_IV_LENGTH];
+       unsigned char                   tag[EVP_GCM_TLS_TAG_LEN];
+       uint8_t                         data[sizeof(eap_fast_attr_pac_opaque_plaintext_t) * 2]; // space for EVP
+} CC_HINT(__packed__) eap_fast_attr_pac_opaque_t;
+
+typedef struct eap_fast_attr_pac_info_t {
+       eap_fast_pac_attr_hdr_t         hdr;
+       eap_fast_pac_attr_lifetime_t    lifetime;
+       eap_fast_pac_attr_a_id_t        a_id;
+       eap_fast_pac_attr_a_id_info_t   a_id_info;
+       eap_fast_pac_attr_pac_type_t    type;
+} CC_HINT(__packed__) eap_fast_attr_pac_info_t;
+
+typedef struct eap_fast_pac_t {
+       eap_fast_pac_attr_pac_key_t     key;
+       eap_fast_attr_pac_info_t        info;
+       eap_fast_attr_pac_opaque_t      opaque; // has to be last!
+} CC_HINT(__packed__) eap_fast_pac_t;
+
+/* RFC 4851, Section 4.2.8 - Crypto-Binding TLV */
+typedef struct eap_tlv_crypto_binding_tlv_t {
+        uint16_t tlv_type;
+        uint16_t length;
+        uint8_t reserved;
+        uint8_t version;
+        uint8_t received_version;
+        uint8_t subtype;
+        uint8_t nonce[32];
+        uint8_t compound_mac[20];
+} CC_HINT(__packed__) eap_tlv_crypto_binding_tlv_t;
+
+typedef enum eap_fast_tlv_type_t {
+       EAP_FAST_TLV_RESERVED_0 = 0,    // 0
+       EAP_FAST_TLV_RESERVED_1,        // 1
+       EAP_FAST_TLV_RESERVED_2,        // 2
+       EAP_FAST_TLV_RESULT,            // 3
+       EAP_FAST_TLV_NAK,               // 4
+       EAP_FAST_TLV_ERROR,             // 5
+       EAP_FAST_TLV_RESERVED6,         // 6
+       EAP_FAST_TLV_VENDOR_SPECIFIC,   // 7
+       EAP_FAST_TLV_RESERVED8,         // 8
+       EAP_FAST_TLV_EAP_PAYLOAD,       // 9
+       EAP_FAST_TLV_INTERMED_RESULT,   // 10
+       EAP_FAST_TLV_PAC,               // 11
+       EAP_FAST_TLV_CRYPTO_BINDING,    // 12
+       EAP_FAST_TLV_RESERVED_13,       // 13
+       EAP_FAST_TLV_RESERVED_14,       // 14
+       EAP_FAST_TLV_RESERVED_15,       // 15
+       EAP_FAST_TLV_RESERVED_16,       // 16
+       EAP_FAST_TLV_RESERVED_17,       // 17
+       EAP_FAST_TLV_TRUSTED_ROOT,      // 18
+       EAP_FAST_TLV_REQ_ACTION,        // 19
+       EAP_FAST_TLV_PKCS,              // 20
+       EAP_FAST_TLV_MAX
+} eap_fast_tlv_type_t;
+
+typedef enum eap_fast_tlv_crypto_binding_tlv_subtype_t {
+       EAP_FAST_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST = 0,        // 0
+       EAP_FAST_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE            // 1
+} eap_fast_tlv_crypto_binding_tlv_subtype_t;
+
+/* RFC 5422: Section 3.3 - Key Derivations Used in the EAP-FAST Provisioning Exchange */
+typedef struct eap_fast_keyblock_t {
+       uint8_t session_key_seed[EAP_FAST_SKS_LEN];
+       uint8_t server_challenge[CHAP_VALUE_LENGTH];
+       uint8_t client_challenge[CHAP_VALUE_LENGTH];
+} CC_HINT(__packed__) eap_fast_keyblock_t;
+
+typedef struct eap_fast_tunnel_t {
+       VALUE_PAIR              *username;
+       VALUE_PAIR      *state;
+       VALUE_PAIR      *accept_vps;
+       bool            copy_request_to_tunnel;
+       bool            use_tunneled_reply;
+
+       bool                    authenticated;
+
+       int                     mode;
+       eap_fast_stage_t        stage;
+       eap_fast_keyblock_t     *keyblock;
+       uint8_t                 *simck;
+       uint8_t                 *cmk;
+       int                     imckc;
+       struct {
+               uint8_t         mppe_send[CHAP_VALUE_LENGTH];
+               uint8_t         mppe_recv[CHAP_VALUE_LENGTH];
+       } CC_HINT(__packed__)   isk;
+       uint8_t                 *msk;
+       uint8_t                 *emsk;
+
+       int                     default_method;
+
+       uint32_t                pac_lifetime;
+       char const              *authority_identity;
+       uint8_t const           *a_id;
+       uint8_t const           *pac_opaque_key;
+
+       struct {
+               uint8_t                 *key;
+               eap_fast_pac_type_t     type;
+               uint32_t                expires;
+               bool                    expired;
+               bool                    send;
+       }                       pac;
+
+       bool                    result_final;
+
+#ifdef WITH_PROXY
+       bool            proxy_tunneled_request_as_eap;  //!< Proxy tunneled session as EAP, or as de-capsulated
+                                                       //!< protocol.
+#endif
+       char const      *virtual_server;
+} eap_fast_tunnel_t;
+
+/*
+ *     Process the FAST portion of an EAP-FAST request.
+ */
+void eap_fast_tlv_append(tls_session_t *tls_session, int tlv, bool mandatory,
+                        int length, const void *data) CC_HINT(nonnull);
+PW_CODE eap_fast_process(eap_handler_t *eap_session, tls_session_t *tls_session) CC_HINT(nonnull);
+
+/*
+ *     A bunch of EAP-FAST helper functions.
+ */
+VALUE_PAIR *eap_fast_fast2vp(REQUEST *request, UNUSED SSL *ssl, uint8_t const *data,
+                            size_t data_len, DICT_ATTR const *fast_da, vp_cursor_t *out);
+
+#endif /* _EAP_FAST_H */
diff --git a/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast_crypto.c b/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast_crypto.c
new file mode 100644 (file)
index 0000000..6cc9852
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * fast-crypto.c  Cryptographic functions for EAP-FAST.
+ *
+ * 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 2016 Alan DeKok <aland@freeradius.org>
+ * Copyright 2016 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API      /* OpenSSL API has been deprecated by Apple */
+
+#include <stdio.h>
+#include <freeradius-devel/libradius.h>
+
+#include <openssl/evp.h>
+#include <openssl/aes.h>
+#include <openssl/err.h>
+
+#include "eap_fast_crypto.h"
+
+// http://stackoverflow.com/a/29838852
+static void NEVER_RETURNS handleErrors(void)
+{
+       unsigned long errCode;
+
+       fprintf(stderr, "An error occurred\n");
+       while((errCode = ERR_get_error()))
+       {
+               char *err = ERR_error_string(errCode, NULL);
+               fprintf(stderr, "%s\n", err);
+       }
+       abort();
+}
+
+// https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Encryption_using_GCM_mode
+int eap_fast_encrypt(uint8_t const *plaintext, size_t plaintext_len,
+                    uint8_t const *aad, size_t aad_len,
+                    uint8_t const *key, uint8_t *iv, unsigned char *ciphertext,
+                    uint8_t *tag)
+{
+       EVP_CIPHER_CTX *ctx;
+
+       int len;
+
+       int ciphertext_len;
+
+
+       /* Create and initialise the context */
+       if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
+
+       /* Initialise the encryption operation. */
+       if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
+               handleErrors();
+
+       /* Set IV length if default 12 bytes (96 bits) is not appropriate */
+       if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL))
+               handleErrors();
+
+       /* Initialise key and IV */
+       if (1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();
+
+       /* Provide any AAD data. This can be called zero or more times as
+        * required
+        */
+       if (1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
+               handleErrors();
+
+       /* Provide the message to be encrypted, and obtain the encrypted output.
+        * EVP_EncryptUpdate can be called multiple times if necessary
+        */
+       if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
+               handleErrors();
+       ciphertext_len = len;
+
+       /* Finalise the encryption. Normally ciphertext bytes may be written at
+        * this stage, but this does not occur in GCM mode
+        */
+       if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
+       ciphertext_len += len;
+
+       /* Get the tag */
+       if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
+               handleErrors();
+
+       /* Clean up */
+       EVP_CIPHER_CTX_free(ctx);
+
+       return ciphertext_len;
+}
+
+int eap_fast_decrypt(uint8_t const *ciphertext, size_t ciphertext_len,
+                    uint8_t const *aad, size_t aad_len,
+                    uint8_t const *tag, uint8_t const *key, uint8_t const *iv, uint8_t *plaintext)
+{
+       EVP_CIPHER_CTX *ctx;
+       int len;
+       int plaintext_len;
+       int ret;
+
+       /* Create and initialise the context */
+       if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
+
+       /* Initialise the decryption operation. */
+       if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
+               handleErrors();
+
+       /* Set IV length. Not necessary if this is 12 bytes (96 bits) */
+       if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL))
+               handleErrors();
+
+       /* Initialise key and IV */
+       if (!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();
+
+       /* Provide any AAD data. This can be called zero or more times as
+        * required
+        */
+       if (!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
+               handleErrors();
+
+       /* Provide the message to be decrypted, and obtain the plaintext output.
+        * EVP_DecryptUpdate can be called multiple times if necessary
+        */
+       if (!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
+               handleErrors();
+       plaintext_len = len;
+
+       {
+               unsigned char *tmp;
+
+               memcpy(&tmp, &tag, sizeof(tmp));
+
+               /* Set expected tag value. Works in OpenSSL 1.0.1d and later */
+               if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tmp)) handleErrors();
+       }
+
+       /* Finalise the decryption. A positive return value indicates success,
+        * anything else is a failure - the plaintext is not trustworthy.
+        */
+       ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
+
+       /* Clean up */
+       EVP_CIPHER_CTX_free(ctx);
+
+       if (ret > 0)
+       {
+               /* Success */
+               plaintext_len += len;
+               return plaintext_len;
+       }
+       else
+       {
+               /* Verify failed */
+               return -1;
+       }
+}
diff --git a/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast_crypto.h b/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast_crypto.h
new file mode 100644 (file)
index 0000000..c2f40dd
--- /dev/null
@@ -0,0 +1,8 @@
+int eap_fast_encrypt(uint8_t const *plaintext, size_t plaintext_len,
+                    uint8_t const *aad, size_t aad_len,
+                    uint8_t const *key, uint8_t *iv, unsigned char *ciphertext,
+                    uint8_t *tag);
+
+int eap_fast_decrypt(uint8_t const *ciphertext, size_t ciphertext_len,
+                    uint8_t const *aad, size_t aad_len,
+                    uint8_t const *tag, uint8_t const *key, uint8_t const *iv, uint8_t *plaintext);
diff --git a/src/modules/rlm_eap/types/rlm_eap_fast/rlm_eap_fast.c b/src/modules/rlm_eap/types/rlm_eap_fast/rlm_eap_fast.c
new file mode 100644 (file)
index 0000000..713b47e
--- /dev/null
@@ -0,0 +1,584 @@
+/*
+ * rlm_eap_fast.c  contains the interfaces that are called from eap
+ *
+ * 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 2016 Alan DeKok <aland@freeradius.org>
+ * Copyright 2016 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API      /* OpenSSL API has been deprecated by Apple */
+
+
+#include "eap_fast.h"
+#include "eap_fast_crypto.h"
+
+
+#include <freeradius-devel/md5.h>
+
+/*
+ *     An instance of EAP-FAST
+ */
+typedef struct rlm_eap_fast_t {
+       char const              *tls_conf_name;                         //!< Name of shared TLS config.
+       fr_tls_server_conf_t *tls_conf;
+
+       char const              *default_method_name;
+       int                     default_method;
+
+       char const              *virtual_server;                        //!< Virtual server to use for processing
+                                                                       //!< inner EAP method.
+       bool                    req_client_cert;                        //!< Whether we require a client cert
+                                                                       //!< in the outer tunnel.
+
+       int                     stage;                                  //!< Processing stage.
+
+       uint32_t pac_lifetime;                          //!< seconds to add to current time to describe PAC lifetime
+       char const              *authority_identity;                    //!< The identity we present in the EAP-TLS
+       uint8_t                 a_id[PAC_A_ID_LENGTH];                  //!< The identity we present in the EAP-TLS
+       char const              *pac_opaque_key;                        //!< The key used to encrypt PAC-Opaque
+       bool use_tunneled_reply;                //!< Use the reply attributes from the tunneled session in
+                                               //!< the non-tunneled reply to the client.
+
+       bool copy_request_to_tunnel;            //!< Use SOME of the request attributes from outside of the
+} rlm_eap_fast_t;
+
+
+static CONF_PARSER module_config[] = {
+       { "tls", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_fast_t, tls_conf_name), NULL },
+
+       { "default_eap_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_fast_t, default_method_name), "mschapv2" },
+
+       { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED | PW_TYPE_NOT_EMPTY, rlm_eap_fast_t, virtual_server) , NULL},
+
+       { "require_client_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_fast_t, req_client_cert), "no" },
+
+       { "pac_lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_fast_t, pac_lifetime), "604800" },
+       { "authority_identity", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_eap_fast_t, authority_identity), NULL },
+       { "pac_opaque_key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_eap_fast_t, pac_opaque_key), NULL },
+       { "copy_request_to_tunnel", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_fast_t, copy_request_to_tunnel), "no" },
+
+       { "use_tunneled_reply", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_fast_t, use_tunneled_reply), "no" },
+
+       CONF_PARSER_TERMINATOR
+};
+
+/*
+ *     Attach the module.
+ */
+static int mod_instantiate(CONF_SECTION *cs, void **instance)
+{
+       rlm_eap_fast_t *inst;
+
+       *instance = inst = talloc_zero(cs, rlm_eap_fast_t);
+       if (!inst) return -1;
+
+       /*
+        *      Parse the configuration attributes.
+        */
+       if (cf_section_parse(cs, inst, module_config) < 0) {
+               return -1;
+       }
+
+       if (!cf_section_sub_find_name2(main_config.config, "server", inst->virtual_server)) {
+               ERROR("rlm_eap_fast.virtual_server: Unknown virtual server '%s'", inst->virtual_server);
+               return -1;
+       }
+
+       inst->default_method = eap_name2type(inst->default_method_name);
+       if (!inst->default_method) {
+               ERROR("rlm_eap_fast.default_provisioning_eap_type: "
+                         "Unknown EAP type %s",
+                                  inst->default_method_name);
+               return -1;
+       }
+
+       /*
+        *      Read tls configuration, either from group given by 'tls'
+        *      option, or from the eap-tls configuration.
+        */
+       inst->tls_conf = eaptls_conf_parse(cs, "tls");
+
+       if (!inst->tls_conf) {
+               ERROR("rlm_eap_fast.tls: Failed initializing SSL context");
+               return -1;
+       }
+
+       if (talloc_array_length(inst->pac_opaque_key) - 1 != 32) {
+               ERROR("rlm_eap_fast.pac_opaque_key: Must be 32 bytes long");
+               return -1;
+       }
+
+       // FIXME TLSv1.2 uses a different PRF and SSL_export_keying_material("key expansion") is forbidden
+       if (!inst->tls_conf->disable_tlsv1_2) {
+               ERROR("rlm_eap_fast.disable_tlsv1_2: require disable_tlsv1_2=yes");
+               return -1;
+       }
+
+       if (!inst->pac_lifetime) {
+               ERROR("rlm_eap_fast.pac_lifetime: must be non-zero");
+               return -1;
+       }
+
+       rad_assert(PAC_A_ID_LENGTH == MD5_DIGEST_LENGTH);
+       FR_MD5_CTX ctx;
+       fr_md5_init(&ctx);
+       fr_md5_update(&ctx, inst->authority_identity, talloc_array_length(inst->authority_identity) - 1);
+       fr_md5_final(inst->a_id, &ctx);
+
+       return 0;
+}
+
+/** Allocate the FAST per-session data
+ *
+ */
+static eap_fast_tunnel_t *eap_fast_alloc(TALLOC_CTX *ctx, rlm_eap_fast_t *inst)
+{
+       eap_fast_tunnel_t *t = talloc_zero(ctx, eap_fast_tunnel_t);
+
+       t->mode = EAP_FAST_UNKNOWN;
+       t->stage = TLS_SESSION_HANDSHAKE;
+
+       t->default_method = inst->default_method;
+       t->copy_request_to_tunnel = inst->copy_request_to_tunnel;
+       t->use_tunneled_reply = inst->use_tunneled_reply;
+
+       t->pac_lifetime = inst->pac_lifetime;
+       t->authority_identity = inst->authority_identity;
+       t->a_id = inst->a_id;
+       t->pac_opaque_key = (const uint8_t *)inst->pac_opaque_key;
+
+       t->virtual_server = inst->virtual_server;
+
+       return t;
+}
+
+static void eap_fast_session_ticket(tls_session_t *tls_session, uint8_t *client_random,
+                                       uint8_t *server_random, uint8_t *secret, int *secret_len)
+{
+       eap_fast_tunnel_t       *t = (eap_fast_tunnel_t *) tls_session->opaque;
+       uint8_t                 seed[2 * SSL3_RANDOM_SIZE];
+
+       rad_assert(t->pac.key);
+
+       memcpy(seed, server_random, SSL3_RANDOM_SIZE);
+       memcpy(&seed[SSL3_RANDOM_SIZE], client_random, SSL3_RANDOM_SIZE);
+
+       T_PRF(t->pac.key, PAC_KEY_LENGTH, "PAC to master secret label hash",
+                 seed, sizeof(seed), secret, SSL_MAX_MASTER_KEY_LENGTH);
+       *secret_len = SSL_MAX_MASTER_KEY_LENGTH;
+}
+
+// hostap:src/crypto/tls_openssl.c:tls_sess_sec_cb()
+static int _session_secret(SSL *s, void *secret, int *secret_len,
+                          UNUSED STACK_OF(SSL_CIPHER) *peer_ciphers,
+                          UNUSED SSL_CIPHER **cipher, void *arg)
+{
+       // FIXME enforce non-anon cipher
+
+       REQUEST         *request = (REQUEST *)SSL_get_ex_data(s, FR_TLS_EX_INDEX_REQUEST);
+       tls_session_t   *tls_session = arg;
+       eap_fast_tunnel_t       *t;
+
+       if (!tls_session) return 0;
+
+       t = (eap_fast_tunnel_t *) tls_session->opaque;
+
+       if (!t->pac.key) return 0;
+
+       RDEBUG("processing PAC-Opaque");
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+       eap_fast_session_ticket(tls_session, s->s3->client_random, s->s3->server_random, secret, secret_len);
+#else
+       uint8_t const client_random[SSL3_RANDOM_SIZE];
+       uint8_t const server_random[SSL3_RANDOM_SIZE];
+
+       SSL_get_client_random(s, client_random, sizeof(client_random));
+       SSL_get_server_random(s, server_random, sizeof(server_random));
+
+       eap_fast_session_ticket(tls_session, client_random, server_random, secret, secret_len);
+#endif
+
+       memset(t->pac.key, 0, PAC_KEY_LENGTH);
+       talloc_free(t->pac.key);
+       t->pac.key = NULL;
+
+       return 1;
+}
+
+/*
+ * hints from hostap:src/crypto/tls_openssl.c:tls_session_ticket_ext_cb()
+ *
+ * N.B. we actually always tell OpenSSL we have digested the ticket so that
+ *      it does not cause a fail loop and enables us to update the PAC easily
+ *
+ */
+static int _session_ticket(SSL *s, uint8_t const *data, int len, void *arg)
+{
+       tls_session_t           *tls_session = arg;
+       REQUEST                 *request = (REQUEST *)SSL_get_ex_data(s, FR_TLS_EX_INDEX_REQUEST);
+       eap_fast_tunnel_t       *t;
+       VALUE_PAIR              *fast_vps = NULL;
+       vp_cursor_t             cursor;
+       DICT_ATTR const *fast_da;
+       char const              *errmsg;
+       int                     dlen, plen;
+       uint16_t                length;
+       eap_fast_attr_pac_opaque_t const        *opaque = (eap_fast_attr_pac_opaque_t const *) data;
+       eap_fast_attr_pac_opaque_t              opaque_plaintext;
+
+       if (!tls_session) return 0;
+
+       t = (eap_fast_tunnel_t *) tls_session->opaque;
+
+       RDEBUG("PAC provided via ClientHello SessionTicket extension");
+
+       if ((ntohs(opaque->hdr.type) & EAP_FAST_TLV_TYPE) != PAC_INFO_PAC_OPAQUE) {
+               errmsg = "PAC is not of type Opaque";
+error:
+               RERROR("%s, sending alert to client", errmsg);
+               /*
+               if (tls_session_handshake_alert(request, tls_session, SSL3_AL_FATAL, SSL_AD_BAD_CERTIFICATE)) {
+                       RERROR("too many alerts");
+                       return 0;
+               }
+               */
+               if (t->pac.key) talloc_free(t->pac.key);
+
+               memset(&t->pac, 0, sizeof(t->pac));
+               if (fast_vps) fr_pair_list_free(&fast_vps);
+               return 1;
+       }
+
+       /*
+        * we would like to use the length of the SessionTicket
+        * but Cisco hates everyone and sends a zero padding payload
+        * so we have to use the length in the PAC-Opaque header
+        */
+       length = ntohs(opaque->hdr.length);
+       if (len - sizeof(opaque->hdr) < length) {
+               errmsg = "PAC has bad length in header";
+               goto error;
+       }
+
+       if (length < PAC_A_ID_LENGTH + EVP_MAX_IV_LENGTH + EVP_GCM_TLS_TAG_LEN + 1) {
+               errmsg = "PAC file too short";
+               goto error;
+       }
+
+       if (memcmp(opaque->aad, t->a_id, PAC_A_ID_LENGTH)) {
+               errmsg = "PAC has incorrect A_ID";
+               goto error;
+       }
+
+       dlen = length - sizeof(opaque->aad) - sizeof(opaque->iv) - sizeof(opaque->tag);
+       plen = eap_fast_decrypt(opaque->data, dlen, opaque->aad, PAC_A_ID_LENGTH,
+                                       (uint8_t const *) opaque->tag, t->pac_opaque_key, opaque->iv,
+                                       (uint8_t *)&opaque_plaintext);
+       if (plen == -1) {
+               errmsg = "PAC failed to decrypt";
+               goto error;
+       }
+
+       fast_da = dict_attrbyname("FreeRADIUS-EAP-FAST-PAC-Opaque-TLV");
+       rad_assert(fast_da != NULL);
+
+       fast_vps = eap_fast_fast2vp((REQUEST *)tls_session, s, (uint8_t *)&opaque_plaintext, plen, fast_da, NULL);
+       if (!fast_vps) return 0;
+
+       for (VALUE_PAIR *vp = fr_cursor_init(&cursor, &fast_vps); vp; vp = fr_cursor_next(&cursor)) {
+               char *value;
+
+               switch ((vp->da->attr >> fr_attr_shift[3]) & fr_attr_mask[3]) {
+               case PAC_INFO_PAC_TYPE:
+                       rad_assert(t->pac.type == 0);
+                       t->pac.type = vp->vp_integer;
+                       break;
+               case PAC_INFO_PAC_LIFETIME:
+                       rad_assert(t->pac.expires == 0);
+                       t->pac.expires = vp->vp_integer;
+                       t->pac.expired = (vp->vp_integer <= time(NULL));
+                       break;
+               case PAC_INFO_PAC_KEY:
+                       rad_assert(t->pac.key == NULL);
+                       rad_assert(vp->vp_length == PAC_KEY_LENGTH);
+                       t->pac.key = talloc_size(t, PAC_KEY_LENGTH);
+                       rad_assert(t->pac.key != NULL);
+                       memcpy(t->pac.key, vp->vp_octets, PAC_KEY_LENGTH);
+                       break;
+               default:
+                       value = vp_aprints(tls_session, vp, '"');
+                       RERROR("unknown TLV: %s", value);
+                       talloc_free(value);
+                       errmsg = "unknown TLV";
+                       goto error;
+               }
+       }
+
+       fr_pair_list_free(&fast_vps);
+
+       if (!t->pac.type) {
+               errmsg = "PAC missing type TLV";
+               goto error;
+       }
+
+       if (t->pac.type != PAC_TYPE_TUNNEL) {
+               errmsg = "PAC is of not of tunnel type";
+               goto error;
+       }
+
+       if (!t->pac.expires) {
+               errmsg = "PAC missing lifetime TLV";
+               goto error;
+       }
+
+       if (!t->pac.key) {
+               errmsg = "PAC missing key TLV";
+               goto error;
+       }
+
+       if (!SSL_set_session_secret_cb(tls_session->ssl, _session_secret, tls_session)) {
+               RERROR("Failed setting SSL session secret callback");
+               return 0;
+       }
+
+       return 1;
+}
+
+
+/*
+ *     Do authentication, by letting EAP-TLS do most of the work.
+ */
+static int mod_process(void *arg, eap_handler_t *handler)
+{
+       int rcode;
+       fr_tls_status_t status;
+       rlm_eap_fast_t *inst = (rlm_eap_fast_t *) arg;
+       tls_session_t *tls_session = (tls_session_t *) handler->opaque;
+       eap_fast_tunnel_t *t = (eap_fast_tunnel_t *) tls_session->opaque;
+       REQUEST *request = handler->request;
+
+       RDEBUG2("Authenticate");
+
+       /*
+        *      We need FAST data associated with the session, so
+        *      allocate it here, if it wasn't already alloacted.
+        */
+       if (!t) t = tls_session->opaque = eap_fast_alloc(tls_session, inst);
+
+       /*
+        *      Process TLS layer until done.
+        */
+       status = eaptls_process(handler);
+       if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
+               REDEBUG("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
+       } else {
+               RDEBUG2("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
+       }
+
+       switch (status) {
+       /*
+        *      EAP-TLS handshake was successful, tell the
+        *      client to keep talking.
+        *
+        *      If this was EAP-TLS, we would just return
+        *      an EAP-TLS-Success packet here.
+        */
+       case FR_TLS_SUCCESS:
+               tls_handshake_send(request, tls_session);
+               rad_assert(t != NULL);
+               break;
+
+       /*
+        *      The TLS code is still working on the TLS
+        *      exchange, and it's a valid TLS request.
+        *      do nothing.
+        */
+       case FR_TLS_HANDLED:
+               return 1;
+
+       /*
+        *      Handshake is done, proceed with decoding tunneled
+        *      data.
+        */
+       case FR_TLS_OK:
+               break;
+
+       /*
+        *      Anything else: fail.
+        */
+       default:
+               return 0;
+       }
+
+       /*
+        *      Session is established, proceed with decoding
+        *      tunneled data.
+        */
+       RDEBUG2("Session established.  Proceeding to decode tunneled attributes");
+
+       /*
+        *      Process the FAST portion of the request.
+        */
+       rcode = eap_fast_process(handler, tls_session);
+
+       switch (rcode) {
+       case PW_CODE_ACCESS_REJECT:
+               RDEBUG("Reject");
+               eaptls_fail(handler, EAP_FAST_VERSION);
+               return 0;
+
+               /*
+                *      Access-Challenge, continue tunneled conversation.
+                */
+       case PW_CODE_ACCESS_CHALLENGE:
+               RDEBUG("Challenge");
+               tls_handshake_send(request, tls_session);
+               eaptls_request(handler->eap_ds, tls_session);
+               return 1;
+
+               /*
+                *      Success: Automatically return MPPE keys.
+                */
+       case PW_CODE_ACCESS_ACCEPT:
+               RDEBUG("Note that the 'missing PRF label' message below is harmless. Please ignore it.");
+               if (t->accept_vps) {
+                       RDEBUG2("Using saved attributes from the original Access-Accept");
+                       rdebug_pair_list(L_DBG_LVL_2, request, t->accept_vps, NULL);
+                       fr_pair_list_mcopy_by_num(handler->request->reply,
+                                 &handler->request->reply->vps,
+                                 &t->accept_vps, 0, 0, TAG_ANY);
+               } else if (t->use_tunneled_reply) {
+                       RDEBUG2("No saved attributes in the original Access-Accept");
+               }
+               return eaptls_success(handler, EAP_FAST_VERSION);
+
+               /*
+                *      No response packet, MUST be proxying it.
+                *      The main EAP module will take care of discovering
+                *      that the request now has a "proxy" packet, and
+                *      will proxy it, rather than returning an EAP packet.
+                */
+       case PW_CODE_STATUS_CLIENT:
+#ifdef WITH_PROXY
+               rad_assert(handler->request->proxy != NULL);
+#endif
+               return 1;
+
+       default:
+               break;
+       }
+
+       /*
+        *      Something we don't understand: Reject it.
+        */
+       eaptls_fail(handler, EAP_FAST_VERSION);
+       return 0;
+}
+
+static int eap_fast_tls_start(EAP_DS * eap_ds,tls_session_t *tls_session)
+{
+       EAPTLS_PACKET   reply;
+
+       reply.code = FR_TLS_START;
+       reply.length = TLS_HEADER_LEN + 1 + tls_session->clean_in.used;/*flags*/
+
+       reply.flags = tls_session->peap_flag;
+       reply.flags = SET_START(reply.flags);
+
+       reply.data = tls_session->clean_in.data;
+       reply.dlen = tls_session->clean_in.used;
+
+       eaptls_compose(eap_ds, &reply);
+
+       return 1;
+}
+
+
+/*
+ *     Send an initial eap-tls request to the peer, using the libeap functions.
+ */
+static int mod_session_init(void *type_arg, eap_handler_t *handler)
+{
+       int                     rcode;
+       tls_session_t           *tls_session;
+       rlm_eap_fast_t          *inst;
+       VALUE_PAIR              *vp;
+       bool                    client_cert;
+       REQUEST                 *request = handler->request;
+
+       inst = type_arg;
+
+       handler->tls = true;
+
+       /*
+        *      EAP-TLS-Require-Client-Cert attribute will override
+        *      the require_client_cert configuration option.
+        */
+       vp = fr_pair_find_by_num(handler->request->config, PW_EAP_TLS_REQUIRE_CLIENT_CERT, 0, TAG_ANY);
+       if (vp) {
+               client_cert = vp->vp_integer ? true : false;
+       } else {
+               client_cert = inst->req_client_cert;
+       }
+       handler->opaque = tls_session = eaptls_session(handler, inst->tls_conf, client_cert);
+
+       if (!tls_session) return 0;
+
+       /*
+        *      Push TLV of authority_identity into tls_record
+        *      call eap_tls_compose() with args
+        *
+        *      RFC 4851 section 4.1.1
+        *      N.B. mandatory/reserved flags are not applicable here
+        */
+       eap_fast_tlv_append(tls_session, PAC_INFO_A_ID, false, PAC_A_ID_LENGTH, inst->a_id);
+       tls_session->peap_flag = EAP_FAST_VERSION;
+       tls_session->length_flag = false;
+       rcode = eap_fast_tls_start(handler->eap_ds, tls_session);
+
+       if (rcode < 0) {
+               talloc_free(tls_session);
+               return 0;
+       }
+
+       tls_session->record_init(&tls_session->clean_in);
+
+       if (!SSL_set_session_ticket_ext_cb(tls_session->ssl, _session_ticket, tls_session)) {
+               RERROR("Failed setting SSL session ticket callback");
+               return 0;
+       }
+
+       handler->stage = PROCESS;
+
+       return 1;
+}
+
+
+/*
+ *     The module name should be the only globally exported symbol.
+ *     That is, everything else should be 'static'.
+ */
+extern rlm_eap_module_t rlm_eap_fast;
+rlm_eap_module_t rlm_eap_fast = {
+       .name           = "eap_fast",
+       .instantiate    = mod_instantiate,      /* Create new submodule instance */
+       .session_init   = mod_session_init,     /* Initialise a new EAP session */
+       .process        = mod_process           /* Process next round of EAP method */
+};
index 454e1e7..031eba2 100644 (file)
@@ -196,7 +196,6 @@ static int CC_HINT(nonnull) mod_process(void *instance, eap_handler_t *handler)
                 */
        } else if (eap_ds->response->type.length <= 128) {
                int rcode;
-               char *p;
 
                /*
                 *      If there was a User-Password in the request,
@@ -208,11 +207,8 @@ static int CC_HINT(nonnull) mod_process(void *instance, eap_handler_t *handler)
                if (!vp) {
                        return 0;
                }
-               vp->vp_length = eap_ds->response->type.length;
-               vp->vp_strvalue = p = talloc_array(vp, char, vp->vp_length + 1);
-               vp->type = VT_DATA;
-               memcpy(p, eap_ds->response->type.data, vp->vp_length);
-               p[vp->vp_length] = 0;
+
+               fr_pair_value_bstrncpy(vp, eap_ds->response->type.data, eap_ds->response->type.length);
 
                /*
                 *      Add the password to the request, and allow
index 7277462..2fa0077 100644 (file)
@@ -116,7 +116,7 @@ static int mod_process(UNUSED void *arg, eap_handler_t *handler)
 
        password = fr_pair_find_by_num(handler->request->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
        if (!password) {
-               RDEBUG2("Cleartext-Password is required for EAP-MD5 authentication");
+               REDEBUG2("Cleartext-Password is required for EAP-MD5 authentication");
                return 0;
        }
 
index 8cf9094..c1a0045 100644 (file)
@@ -33,6 +33,7 @@ typedef struct rlm_eap_mschapv2_t {
        bool with_ntdomain_hack;
        bool send_error;
        char const *identity;
+       int  auth_type_mschap;
 } rlm_eap_mschapv2_t;
 
 static CONF_PARSER module_config[] = {
@@ -58,6 +59,7 @@ static void fix_mppe_keys(eap_handler_t *handler, mschapv2_opaque_t *data)
 static int mod_instantiate(CONF_SECTION *cs, void **instance)
 {
        rlm_eap_mschapv2_t *inst;
+       DICT_VALUE const *dv;
 
        *instance = inst = talloc_zero(cs, rlm_eap_mschapv2_t);
        if (!inst) return -1;
@@ -78,6 +80,14 @@ static int mod_instantiate(CONF_SECTION *cs, void **instance)
                inst->identity = talloc_asprintf(inst, "freeradius-%s", RADIUSD_VERSION_STRING);
        }
 
+       dv = dict_valbyname(PW_AUTH_TYPE, 0, "MSCHAP");
+       if (!dv) dv = dict_valbyname(PW_AUTH_TYPE, 0, "MS-CHAP");
+       if (!dv) {
+               cf_log_err_cs(cs, "Failed to find 'Auth-Type MS-CHAP' section.  Cannot authenticate users.");
+               return -1;
+       }
+       inst->auth_type_mschap = dv->value;
+
        return 0;
 }
 
@@ -535,8 +545,15 @@ failure:
         *      The 'value_size' is the size of the response,
         *      which is supposed to be the response (48
         *      bytes) plus 1 byte of flags at the end.
+        *
+        *      NOTE: When using Cisco NEAT with EAP-MSCHAPv2, the
+        *            switch supplicant will send MSCHAPv2 data (EAP type = 26)
+        *            but will always set a value_size of 16 and NULL out the
+        *            peer challenge.
+        *
         */
-       if (eap_ds->response->type.data[4] != 49) {
+       if ((eap_ds->response->type.data[4] != 49) &&
+           (eap_ds->response->type.data[4] != 16)) {
                REDEBUG("Response is of incorrect length %d", eap_ds->response->type.data[4]);
                return 0;
        }
@@ -640,7 +657,7 @@ packet_ready:
                 */
                if (inst->with_ntdomain_hack &&
                    ((challenge = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY)) != NULL) &&
-                   ((username = strchr(challenge->vp_strvalue, '\\')) != NULL)) {
+                   ((username = memchr(challenge->vp_octets, '\\', challenge->vp_length)) != NULL)) {
                        /*
                         *      Wipe out the NT domain.
                         *
@@ -662,7 +679,7 @@ packet_ready:
        /*
         *      This is a wild & crazy hack.
         */
-       rcode = process_authenticate(PW_AUTH_TYPE_MS_CHAP, request);
+       rcode = process_authenticate(inst->auth_type_mschap, request);
 
        /*
         *      Delete MPPE keys & encryption policy.  We don't
index b456bef..7b803f8 100644 (file)
@@ -72,5 +72,5 @@ typedef struct peap_tunnel_t {
 /*
  *     Process the PEAP portion of an EAP-PEAP request.
  */
-rlm_rcode_t eappeap_process(eap_handler_t *handler, tls_session_t *tls_session) CC_HINT(nonnull);
+rlm_rcode_t eappeap_process(eap_handler_t *handler, tls_session_t *tls_session, int auth_type_eap) CC_HINT(nonnull);
 #endif /* _EAP_PEAP_H */
index 3f575e4..6c885da 100644 (file)
@@ -722,7 +722,7 @@ static void print_tunneled_data(uint8_t const *data, size_t data_len)
 /*
  *     Process the pseudo-EAP contents of the tunneled data.
  */
-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, int auth_type_eap)
 {
        peap_tunnel_t   *t = tls_session->opaque;
        REQUEST         *fake;
@@ -804,7 +804,7 @@ rlm_rcode_t eappeap_process(eap_handler_t *handler, tls_session_t *tls_session)
        case PEAP_STATUS_WAIT_FOR_SOH_RESPONSE:
                fake = request_alloc_fake(request);
                rad_assert(!fake->packet->vps);
-               eapsoh_verify(request, fake->packet, data, data_len);
+               eapsoh_verify(fake, fake->packet, data, data_len);
                setup_fake_request(request, fake, t);
 
                if (t->soh_virtual_server) {
@@ -872,16 +872,15 @@ rlm_rcode_t eappeap_process(eap_handler_t *handler, tls_session_t *tls_session)
                return RLM_MODULE_REJECT;
 
        /*
-        *      Damned if I know why the clients continue sending EAP
-        *      packets after we told them to f*ck off.
+        *      Supplicant ACKs our failure.
         */
        case PEAP_STATUS_SENT_TLV_FAILURE:
                RINDENT();
-               RINFO("The users session was previously rejected: returning reject (again.)");
-               RINFO("This means you need to read the PREVIOUS messages in the debug output");
-               RINFO("to find out the reason why the user was rejected");
-               RINFO("Look for \"reject\" or \"fail\".  Those earlier messages will tell you");
-               RINFO("what went wrong, and how to fix the problem");
+               RIDEBUG("The users session was previously rejected: returning reject (again.)");
+               RIDEBUG("This means you need to read the PREVIOUS messages in the debug output");
+               RIDEBUG("to find out the reason why the user was rejected");
+               RIDEBUG("Look for \"reject\" or \"fail\".  Those earlier messages will tell you");
+               RIDEBUG("what went wrong, and how to fix the problem");
                REXDENT();
 
                return RLM_MODULE_REJECT;
@@ -1047,12 +1046,18 @@ rlm_rcode_t eappeap_process(eap_handler_t *handler, tls_session_t *tls_session)
                                 *      Auth-Type & EAP-Message here?
                                 */
 
+                               if (!auth_type_eap) {
+                                       RERROR("You must set 'inner_eap_module' in the 'peap' configuration");
+                                       RERROR("This is required in order to proxy the inner EAP session.");
+                                       rcode = RLM_MODULE_REJECT;
+                                       goto done;
+                               }
 
                                /*
                                 *      Run the EAP authentication.
                                 */
                                RDEBUG2("Calling authenticate in order to initiate tunneled EAP session");
-                               rcode = process_authenticate(PW_AUTH_TYPE_EAP, fake);
+                               rcode = process_authenticate(auth_type_eap, fake);
                                if (rcode == RLM_MODULE_OK) {
                                        /*
                                         *      Authentication succeeded! Rah!
@@ -1249,7 +1254,7 @@ static int CC_HINT(nonnull) setup_fake_request(REQUEST *request, REQUEST *fake,
                        /*
                         *      Some attributes are handled specially.
                         */
-                       switch (vp->da->attr) {
+                       if (!vp->da->vendor) switch (vp->da->attr) {
                                /*
                                 *      NEVER copy Message-Authenticator,
                                 *      EAP-Message, or State.  They're
index 15ea812..e43c9c7 100644 (file)
@@ -30,6 +30,9 @@ typedef struct rlm_eap_peap_t {
        fr_tls_server_conf_t *tls_conf;
        char const *default_method_name;        //!< Default tunneled EAP type.
        int default_method;
+
+       char const *inner_eap_module;           //!< module name for inner EAP
+       int auth_type_eap;
        bool use_tunneled_reply;                //!< Use the reply attributes from the tunneled session in
                                                //!< the non-tunneled reply to the client.
 
@@ -52,6 +55,8 @@ static CONF_PARSER module_config[] = {
 
        { "default_eap_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_peap_t, default_method_name), "mschapv2" },
 
+       { "inner_eap_module", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_peap_t, inner_eap_module), NULL },
+
        { "copy_request_to_tunnel", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_peap_t, copy_request_to_tunnel), "no" },
 
        { "use_tunneled_reply", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_peap_t, use_tunneled_reply), "no" },
@@ -67,6 +72,7 @@ static CONF_PARSER module_config[] = {
        { "require_client_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_peap_t, req_client_cert), "no" },
 
        { "soh_virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_peap_t, soh_virtual_server), NULL },
+
        CONF_PARSER_TERMINATOR
 };
 
@@ -77,6 +83,7 @@ static CONF_PARSER module_config[] = {
 static int mod_instantiate(CONF_SECTION *cs, void **instance)
 {
        rlm_eap_peap_t          *inst;
+       DICT_VALUE const        *dv;
 
        *instance = inst = talloc_zero(cs, rlm_eap_peap_t);
        if (!inst) return -1;
@@ -88,6 +95,11 @@ static int mod_instantiate(CONF_SECTION *cs, void **instance)
                return -1;
        }
 
+       if (!inst->virtual_server) {
+               ERROR("rlm_eap_peap: A 'virtual_server' MUST be defined for security");
+               return -1;
+       }
+
        /*
         *      Convert the name to an integer, to make it easier to
         *      handle.
@@ -110,6 +122,19 @@ static int mod_instantiate(CONF_SECTION *cs, void **instance)
                return -1;
        }
 
+       /*
+        *      Don't expose this if we don't need it.
+        */
+       if (!inst->inner_eap_module) inst->inner_eap_module = "eap";
+
+       dv = dict_valbyname(PW_AUTH_TYPE, 0, inst->inner_eap_module);
+       if (!dv) {
+               WARN("Failed to find 'Auth-Type %s' section in virtual server %s.  The server cannot proxy inner-tunnel EAP packets.",
+                    inst->inner_eap_module, inst->virtual_server);
+       } else {
+               inst->auth_type_eap = dv->value;
+       }
+
        return 0;
 }
 
@@ -300,7 +325,7 @@ static int mod_process(void *arg, eap_handler_t *handler)
        /*
         *      Process the PEAP portion of the request.
         */
-       rcode = eappeap_process(handler, tls_session);
+       rcode = eappeap_process(handler, tls_session, inst->auth_type_eap);
        switch (rcode) {
        case RLM_MODULE_REJECT:
                eaptls_fail(handler, 0);
index e62d5d8..e04ec27 100644 (file)
@@ -1,8 +1,10 @@
 TARGETNAME     := @targetname@
 
+ifneq "$(OPENSSL_LIBS)" ""
 ifneq "$(TARGETNAME)" ""
 TARGET         := $(TARGETNAME).a
 endif
+endif
 
 SOURCES                := $(TARGETNAME).c eap_pwd.c
 
index 6220bbd..9abae5c 100644 (file)
@@ -279,7 +279,6 @@ static int mod_process(void *arg, eap_handler_t *handler)
        uint8_t exch, *in, *ptr, msk[MSK_EMSK_LEN], emsk[MSK_EMSK_LEN];
        uint8_t peer_confirm[SHA256_DIGEST_LENGTH];
        BIGNUM *x = NULL, *y = NULL;
-       char *p;
 
        if (((eap_ds = handler->eap_ds) == NULL) || !inst) return 0;
 
@@ -426,17 +425,13 @@ static int mod_process(void *arg, eap_handler_t *handler)
                        RDEBUG("pwd unable to create fake request!");
                        return 0;
                }
-               fake->username = pair_make_request("User-Name", NULL, T_OP_EQ);
+               fake->username = fr_pair_afrom_num(fake->packet, PW_USER_NAME, 0);
                if (!fake->username) {
-                       RDEBUG("pwd unanable to create value pair for username!");
+                       RDEBUG("Failed creating pair for peer id");
                        talloc_free(fake);
                        return 0;
                }
-               fake->username->vp_length = session->peer_id_len;
-               fake->username->vp_strvalue = p = talloc_array(fake->username, char, fake->username->vp_length + 1);
-               memcpy(p, session->peer_id, session->peer_id_len);
-               p[fake->username->vp_length] = '\0';
-
+               fr_pair_value_bstrncpy(fake->username, session->peer_id, session->peer_id_len);
                fr_pair_add(&fake->packet->vps, fake->username);
 
                if ((vp = fr_pair_find_by_num(request->config, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) {
index 422db30..d853a08 100644 (file)
@@ -46,13 +46,15 @@ typedef struct eap_sim_server_state {
 /*
  *     build a reply to be sent.
  */
-static int eap_sim_compose(eap_handler_t *handler)
+static void eap_sim_compose(REQUEST *request, eap_handler_t *handler)
 {
        /* we will set the ID on requests, since we have to HMAC it */
        handler->eap_ds->set_request_id = 1;
 
-       return map_eapsim_basictypes(handler->request->reply,
-                                    handler->eap_ds->request);
+       if (!map_eapsim_basictypes(handler->request->reply,
+                                  handler->eap_ds->request)) {
+               REDEBUG("Failed decoding EAP-SIM packet: %s", fr_strerror());
+       }
 }
 
 static int eap_sim_sendstart(eap_handler_t *handler)
@@ -416,9 +418,9 @@ static int eap_sim_sendsuccess(eap_handler_t *handler)
 /** Run the server state machine
  *
  */
-static void eap_sim_stateenter(eap_handler_t *handler,
-                              eap_sim_state_t *ess,
-                              enum eapsim_serverstates newstate)
+static void eap_sim_state_enter(REQUEST *request, eap_handler_t *handler,
+                               eap_sim_state_t *ess,
+                               enum eapsim_serverstates newstate)
 {
        switch (newstate) {
        /*
@@ -452,7 +454,7 @@ static void eap_sim_stateenter(eap_handler_t *handler,
        ess->state = newstate;
 
        /* build the target packet */
-       eap_sim_compose(handler);
+       eap_sim_compose(request, handler);
 }
 
 /*
@@ -480,7 +482,7 @@ static int mod_session_init(UNUSED void *instance, eap_handler_t *handler)
        if (!eap_sim_get_challenge(handler, request->config, 0, ess) ||
            !eap_sim_get_challenge(handler, request->config, 1, ess) ||
            !eap_sim_get_challenge(handler, request->config, 2, ess)) {
-               return 0;
+               return 0;       /* already printed error */
        }
 
        /*
@@ -489,7 +491,7 @@ static int mod_session_init(UNUSED void *instance, eap_handler_t *handler)
        time(&n);
        ess->sim_id = (n & 0xff);
 
-       eap_sim_stateenter(handler, ess, EAPSIM_SERVER_START);
+       eap_sim_state_enter(request, handler, ess, EAPSIM_SERVER_START);
 
        return 1;
 }
@@ -513,8 +515,7 @@ static int process_eap_sim_start(eap_handler_t *handler, VALUE_PAIR *vps)
        selectedversion_vp = fr_pair_find_by_num(vps, PW_EAP_SIM_SELECTED_VERSION, 0, TAG_ANY);
        if (!nonce_vp || !selectedversion_vp) {
                RDEBUG2("Client did not select a version and send a NONCE");
-               eap_sim_stateenter(handler, ess, EAPSIM_SERVER_START);
-
+               eap_sim_state_enter(request, handler, ess, EAPSIM_SERVER_START);
                return 1;
        }
 
@@ -523,7 +524,6 @@ static int process_eap_sim_start(eap_handler_t *handler, VALUE_PAIR *vps)
         */
        if (selectedversion_vp->vp_length < 2) {
                REDEBUG("EAP-SIM version field is too short");
-
                return 0;
        }
        memcpy(&simversion, selectedversion_vp->vp_strvalue, sizeof(simversion));
@@ -550,7 +550,7 @@ static int process_eap_sim_start(eap_handler_t *handler, VALUE_PAIR *vps)
        /*
         *      Everything looks good, change states
         */
-       eap_sim_stateenter(handler, ess, EAPSIM_SERVER_CHALLENGE);
+       eap_sim_state_enter(request, handler, ess, EAPSIM_SERVER_CHALLENGE);
 
        return 1;
 }
@@ -604,7 +604,7 @@ static int process_eap_sim_challenge(eap_handler_t *handler, VALUE_PAIR *vps)
        }
 
        /* everything looks good, change states */
-       eap_sim_stateenter(handler, ess, EAPSIM_SERVER_SUCCESS);
+       eap_sim_state_enter(request, handler, ess, EAPSIM_SERVER_SUCCESS);
        return 1;
 }
 
@@ -632,7 +632,10 @@ static int mod_process(UNUSED void *arg, eap_handler_t *handler)
                                          handler->eap_ds->response->type.data,
                                          handler->eap_ds->response->type.length);
 
-       if (!success) return 0;
+       if (!success) {
+               REDEBUG("Failed decoding EAP-SIM packet: %s", fr_strerror());
+               return 0;
+       }
 
        /*
         *      See what kind of message we have gotten
@@ -659,7 +662,7 @@ static int mod_process(UNUSED void *arg, eap_handler_t *handler)
                 */
                default:
 
-                       eap_sim_stateenter(handler, ess, EAPSIM_SERVER_START);
+                       eap_sim_state_enter(request, handler, ess, EAPSIM_SERVER_START);
                        return 1;
                /*
                 *      A response to our EAP-Sim/Request/Start!
@@ -674,7 +677,7 @@ static int mod_process(UNUSED void *arg, eap_handler_t *handler)
                 *      Pretty much anything else here is illegal, so we will retransmit the request.
                 */
                default:
-                       eap_sim_stateenter(handler, ess, EAPSIM_SERVER_CHALLENGE);
+                       eap_sim_state_enter(request, handler, ess, EAPSIM_SERVER_CHALLENGE);
                        return 1;
                /*
                 *      A response to our EAP-Sim/Request/Challenge!
index c00f7a2..184a8c5 100644 (file)
@@ -103,6 +103,11 @@ static int mod_instantiate(CONF_SECTION *cs, void **instance)
                return -1;
        }
 
+       if (!inst->virtual_server) {
+               ERROR("rlm_eap_ttls: A 'virtual_server' MUST be defined for security");
+               return -1;
+       }
+
        /*
         *      Convert the name to an integer, to make it easier to
         *      handle.
index 63d33a8..912060f 100644 (file)
@@ -1006,7 +1006,7 @@ int eapttls_process(eap_handler_t *handler, tls_session_t *tls_session)
        /*
         *      Tell the request that it's a fake one.
         */
-       pair_make_request("Freeradius-Proxied-To", "127.0.0.1", T_OP_EQ);
+       fr_pair_make(fake->packet, &fake->packet->vps, "Freeradius-Proxied-To", "127.0.0.1", T_OP_EQ);
 
        RDEBUG("Got tunneled request");
        rdebug_pair_list(L_DBG_LVL_1, request, fake->packet->vps, NULL);
@@ -1117,7 +1117,7 @@ int eapttls_process(eap_handler_t *handler, tls_session_t *tls_session)
                        /*
                         *      Some attributes are handled specially.
                         */
-                       switch (vp->da->attr) {
+                       if (!vp->da->vendor) switch (vp->da->attr) {
                        /*
                         *      NEVER copy Message-Authenticator,
                         *      EAP-Message, or State.  They're
index 465bfb1..345a60e 100644 (file)
@@ -293,6 +293,7 @@ static rlm_rcode_t CC_HINT(nonnull) mod_exec_dispatch(void *instance, REQUEST *r
 
        VALUE_PAIR      **input_pairs = NULL, **output_pairs = NULL;
        VALUE_PAIR      *answer = NULL;
+       TALLOC_CTX      *ctx = NULL;
        char            out[1024];
 
        /*
@@ -333,13 +334,15 @@ static rlm_rcode_t CC_HINT(nonnull) mod_exec_dispatch(void *instance, REQUEST *r
                if (!output_pairs) {
                        return RLM_MODULE_INVALID;
                }
+
+               ctx = radius_list_ctx(request, inst->output_list);
        }
 
        /*
         *      This function does it's own xlat of the input program
         *      to execute.
         */
-       status = radius_exec_program(request, out, sizeof(out), inst->output ? &answer : NULL, request,
+       status = radius_exec_program(ctx, out, sizeof(out), inst->output ? &answer : NULL, request,
                                     inst->program, inst->input ? *input_pairs : NULL,
                                     inst->wait, inst->shell_escape, inst->timeout);
        rcode = rlm_exec_status2rcode(request, out, strlen(out), status);
index a7f163b..572f6f6 100644 (file)
@@ -873,8 +873,7 @@ static ssize_t unescape_xlat(UNUSED void *instance, UNUSED REQUEST *request,
  *
  * Probably only works for ASCII
  */
-static ssize_t lc_xlat(UNUSED void *instance, UNUSED REQUEST *request,
-                      char const *fmt, char *out, size_t outlen)
+static ssize_t tolower_xlat(UNUSED void *instance, UNUSED REQUEST *request, char const *fmt, char *out, size_t outlen)
 {
        char *q;
        char const *p;
@@ -898,8 +897,7 @@ static ssize_t lc_xlat(UNUSED void *instance, UNUSED REQUEST *request,
  *
  * Probably only works for ASCII
  */
-static ssize_t uc_xlat(UNUSED void *instance, UNUSED REQUEST *request,
-                      char const *fmt, char *out, size_t outlen)
+static ssize_t toupper_xlat(UNUSED void *instance, UNUSED REQUEST *request, char const *fmt, char *out, size_t outlen)
 {
        char *q;
        char const *p;
@@ -1664,8 +1662,8 @@ static int mod_bootstrap(CONF_SECTION *conf, void *instance)
        xlat_register("urlunquote", urlunquote_xlat, NULL, inst);
        xlat_register("escape", escape_xlat, NULL, inst);
        xlat_register("unescape", unescape_xlat, NULL, inst);
-       xlat_register("tolower", lc_xlat, NULL, inst);
-       xlat_register("toupper", uc_xlat, NULL, inst);
+       xlat_register("tolower", tolower_xlat, NULL, inst);
+       xlat_register("toupper", toupper_xlat, NULL, inst);
        xlat_register("md5", md5_xlat, NULL, inst);
        xlat_register("sha1", sha1_xlat, NULL, inst);
 #ifdef HAVE_OPENSSL_EVP_H
index cadfc60..6aa9ee8 100644 (file)
@@ -1211,10 +1211,9 @@ char const *rlm_ldap_find_user(rlm_ldap_t const *inst, REQUEST *request, ldap_ha
                fr_pair_value_strcpy(vp, dn);
                *rcode = RLM_MODULE_OK;
        }
-
-finish:
        ldap_memfree(dn);
 
+finish:
        if ((freeit || (*rcode != RLM_MODULE_OK)) && *result) {
                ldap_msgfree(*result);
                *result = NULL;
@@ -1328,6 +1327,41 @@ static int rlm_ldap_rebind(LDAP *handle, LDAP_CONST char *url, UNUSED ber_tag_t
 }
 #endif
 
+int rlm_ldap_global_init(rlm_ldap_t *inst)
+{
+       int ldap_errno;
+
+       rad_assert(inst); /* clang scan */
+
+#define do_ldap_global_option(_option, _name, _value) \
+       if (ldap_set_option(NULL, _option, _value) != LDAP_OPT_SUCCESS) { \
+               ldap_get_option(NULL, LDAP_OPT_ERROR_NUMBER, &ldap_errno); \
+               ERROR("Failed setting global option %s: %s", _name, \
+                        (ldap_errno != LDAP_SUCCESS) ? ldap_err2string(ldap_errno) : "Unknown error"); \
+               return -1;\
+       }
+
+#define maybe_ldap_global_option(_option, _name, _value) \
+       if (_value) do_ldap_global_option(_option, _name, _value)
+
+#ifdef LDAP_OPT_DEBUG_LEVEL
+       /*
+        *      Can't use do_ldap_global_option
+        */
+       if (inst->ldap_debug) do_ldap_global_option(LDAP_OPT_DEBUG_LEVEL, "ldap_debug", &(inst->ldap_debug));
+#endif
+
+#ifdef LDAP_OPT_X_TLS_RANDOM_FILE
+       /*
+        *      OpenLDAP will error out if we attempt to set
+        *      this on a handle. Presumably it's global in
+        *      OpenSSL too.
+        */
+       maybe_ldap_global_option(LDAP_OPT_X_TLS_RANDOM_FILE, "random_file", inst->tls_random_file);
+#endif
+       return 0;
+}
+
 /** Close and delete a connection
  *
  * Unbinds the LDAP connection, informing the server and freeing any memory, then releases the memory used by the
@@ -1404,17 +1438,8 @@ void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
                goto error;\
        }
 
-#define do_ldap_global_option(_option, _name, _value) \
-       if (ldap_set_option(NULL, _option, _value) != LDAP_OPT_SUCCESS) { \
-               ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno); \
-               LDAP_ERR("Failed setting global option %s: %s", _name, \
-                        (ldap_errno != LDAP_SUCCESS) ? ldap_err2string(ldap_errno) : "Unknown error"); \
-               goto error;\
-       }
-
-       if (inst->ldap_debug) {
-               do_ldap_global_option(LDAP_OPT_DEBUG_LEVEL, "ldap_debug", &(inst->ldap_debug));
-       }
+#define maybe_ldap_option(_option, _name, _value) \
+       if (_value) do_ldap_option(_option, _name, _value)
 
        /*
         *      Leave "dereference" unset to use the OpenLDAP default.
@@ -1474,9 +1499,6 @@ void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
                do_ldap_option(LDAP_OPT_X_TLS, "tls_mode", &(inst->tls_mode));
        }
 
-#  define maybe_ldap_option(_option, _name, _value) \
-       if (_value) do_ldap_option(_option, _name, _value)
-
        maybe_ldap_option(LDAP_OPT_X_TLS_CACERTFILE, "ca_file", inst->tls_ca_file);
        maybe_ldap_option(LDAP_OPT_X_TLS_CACERTDIR, "ca_path", inst->tls_ca_path);
 
@@ -1486,7 +1508,6 @@ void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
         */
        maybe_ldap_option(LDAP_OPT_X_TLS_CERTFILE, "certificate_file", inst->tls_certificate_file);
        maybe_ldap_option(LDAP_OPT_X_TLS_KEYFILE, "private_key_file", inst->tls_private_key_file);
-       maybe_ldap_option(LDAP_OPT_X_TLS_RANDOM_FILE, "random_file", inst->tls_random_file);
 
 #  ifdef LDAP_OPT_X_TLS_NEVER
        if (inst->tls_require_cert_str) {
index ee17d24..4abaa83 100644 (file)
@@ -417,6 +417,8 @@ ldap_rcode_t rlm_ldap_result(rlm_ldap_t const *inst, ldap_handle_t const *conn,
 
 char *rlm_ldap_berval_to_string(TALLOC_CTX *ctx, struct berval const *in);
 
+int rlm_ldap_global_init(rlm_ldap_t *inst) CC_HINT(nonnull);
+
 void *mod_conn_create(TALLOC_CTX *ctx, void *instance);
 
 ldap_handle_t *mod_conn_get(rlm_ldap_t const *inst, REQUEST *request);
index d70d005..9413026 100644 (file)
@@ -103,8 +103,8 @@ static CONF_PARSER tls_config[] = {
        { "keyfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, rlm_ldap_t, tls_private_key_file), NULL }, // OK if it changes on HUP
        { "private_key_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_ldap_t, tls_private_key_file), NULL }, // OK if it changes on HUP
 
-       { "randfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, rlm_ldap_t, tls_random_file), NULL },
-       { "random_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_ldap_t, tls_random_file), NULL },
+       { "randfile", FR_CONF_OFFSET(PW_TYPE_FILE_EXISTS | PW_TYPE_DEPRECATED, rlm_ldap_t, tls_random_file), NULL },
+       { "random_file", FR_CONF_OFFSET(PW_TYPE_FILE_EXISTS, rlm_ldap_t, tls_random_file), NULL },
 
        /*
         *      LDAP Specific TLS attributes
@@ -213,7 +213,7 @@ static CONF_PARSER option_config[] = {
 
 
 static const CONF_PARSER module_config[] = {
-       { "server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, config_server), NULL },  /* Do not set to required */
+       { "server", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_MULTI, rlm_ldap_t, config_server), NULL },  /* Do not set to required */
        { "port", FR_CONF_OFFSET(PW_TYPE_SHORT, rlm_ldap_t, port), NULL },
 
        { "identity", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, admin_identity), NULL },
@@ -865,7 +865,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                                return -1;
                        }
 
-                       if (ldap_url->lud_dn) {
+                       if (ldap_url->lud_dn && (ldap_url->lud_dn[0] != '\0')) {
                                cf_log_err_cs(conf, "Base DN cannot be specified via server URL");
                                goto ldap_url_error;
                        }
@@ -1168,6 +1168,11 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
        }
 
        /*
+        *      Set global options
+        */
+       if (rlm_ldap_global_init(inst) < 0) goto error;
+
+       /*
         *      Initialize the socket pool.
         */
        inst->pool = fr_connection_pool_module_init(inst->cs, inst, mod_conn_create, NULL, NULL);
index 906b668..3d4219c 100644 (file)
@@ -144,7 +144,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                return -1;
        }
 
-       inst->ef = exfile_init(inst, 64, 30, true);
+       inst->ef = exfile_init(inst, 256, 30, true);
        if (!inst->ef) {
                cf_log_err_cs(conf, "Failed creating log file context");
                return -1;
@@ -162,67 +162,19 @@ static size_t linelog_escape_func(UNUSED REQUEST *request,
                char *out, size_t outlen, char const *in,
                UNUSED void *arg)
 {
-       int len = 0;
-
        if (outlen == 0) return 0;
+
        if (outlen == 1) {
                *out = '\0';
                return 0;
        }
 
-       while (in[0]) {
-               if (in[0] >= ' ') {
-                       if (in[0] == '\\') {
-                               if (outlen <= 2) break;
-                               outlen--;
-                               *out++ = '\\';
-                               len++;
-                       }
-
-                       outlen--;
-                       if (outlen == 1) break;
-                       *out++ = *in++;
-                       len++;
-                       continue;
-               }
-
-               switch (in[0]) {
-               case '\n':
-                       if (outlen <= 2) break;
-                       *out++ = '\\';
-                       *out++ = 'n';
-                       in++;
-                       len += 2;
-                       break;
-
-               case '\r':
-                       if (outlen <= 2) break;
-                       *out++ = '\\';
-                       *out++ = 'r';
-                       in++;
-                       len += 2;
-                       break;
-
-               default:
-                       if (outlen <= 4) break;
-                       snprintf(out, outlen,  "\\%03o", (uint8_t) *in);
-                       in++;
-                       out += 4;
-                       outlen -= 4;
-                       len += 4;
-                       break;
-               }
-       }
-
-       *out = '\0';
-       return len;
+       return fr_prints(out, outlen, in, -1, 0);
 }
 
 static rlm_rcode_t CC_HINT(nonnull) mod_do_linelog(void *instance, REQUEST *request)
 {
        int fd = -1;
-       char *p;
-       char line[4096];
        rlm_linelog_t *inst = (rlm_linelog_t*) instance;
        char const *value = inst->line;
 
@@ -230,6 +182,8 @@ static rlm_rcode_t CC_HINT(nonnull) mod_do_linelog(void *instance, REQUEST *requ
        gid_t gid;
        char *endptr;
 #endif
+       char path[2048];
+       char line[4096];
 
        line[0] = '\0';
 
@@ -237,9 +191,7 @@ static rlm_rcode_t CC_HINT(nonnull) mod_do_linelog(void *instance, REQUEST *requ
                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(line + 1, sizeof(line) - 1, request, inst->reference, linelog_escape_func, NULL) < 0) {
                        return RLM_MODULE_FAIL;
                }
 
@@ -264,8 +216,8 @@ static rlm_rcode_t CC_HINT(nonnull) mod_do_linelog(void *instance, REQUEST *requ
                cp = cf_item_to_pair(ci);
                value = cf_pair_value(cp);
                if (!value) {
-                       RDEBUG2("Entry \"%s\" has no value", line);
-                       goto do_log;
+                       RWDEBUG2("Entry \"%s\" has no value", line);
+                       return RLM_MODULE_OK;
                }
 
                /*
@@ -278,73 +230,54 @@ static rlm_rcode_t CC_HINT(nonnull) mod_do_linelog(void *instance, REQUEST *requ
        /*
         *      FIXME: Check length.
         */
-       if (strcmp(inst->filename, "syslog") != 0) {
-               char path[2048];
-
-               if (radius_xlat(path, sizeof(path), request, inst->filename, inst->escape_func, NULL) < 0) {
-                       return RLM_MODULE_FAIL;
-               }
-
-               /* check path and eventually create subdirs */
-               p = strrchr(path, '/');
-               if (p) {
-                       *p = '\0';
-                       if (rad_mkdir(path, 0700, -1, -1) < 0) {
-                               RERROR("rlm_linelog: Failed to create directory %s: %s", path, fr_syserror(errno));
-                               return RLM_MODULE_FAIL;
-                       }
-                       *p = '/';
-               }
-
-               fd = exfile_open(inst->ef, path, inst->permissions, true);
-               if (fd < 0) {
-                       ERROR("rlm_linelog: Failed to open %s: %s", path, fr_syserror(errno));
-                       return RLM_MODULE_FAIL;
-               }
-
-               if (inst->group != NULL) {
-                       gid = strtol(inst->group, &endptr, 10);
-                       if (*endptr != '\0') {
-                               if (rad_getgid(request, &gid, inst->group) < 0) {
-                                       RDEBUG2("Unable to find system group \"%s\"", inst->group);
-                                       goto skip_group;
-                               }
-                       }
-
-                       if (chown(path, -1, gid) == -1) {
-                               RDEBUG2("Unable to change system group of \"%s\"", path);
-                       }
-               }
+       if (radius_xlat(line, sizeof(line) - 1, request, value, linelog_escape_func, NULL) < 0) {
+               return RLM_MODULE_FAIL;
        }
 
- skip_group:
+#ifdef HAVE_SYSLOG_H
+       if (strcmp(inst->filename, "syslog") == 0) {
+               syslog(inst->syslog_priority, "%s", line);
+               return RLM_MODULE_OK;
+       }
+#endif
 
        /*
-        *      FIXME: Check length.
+        *      We're using a real filename now.
         */
-       if (value && (radius_xlat(line, sizeof(line) - 1, request, value, linelog_escape_func, NULL) < 0)) {
-               if (fd >= 0) exfile_close(inst->ef, fd);
+       if (radius_xlat(path, sizeof(path), request, inst->filename, inst->escape_func, NULL) < 0) {
+               return RLM_MODULE_FAIL;
+       }
 
+       fd = exfile_open(inst->ef, path, inst->permissions, true);
+       if (fd < 0) {
+               ERROR("rlm_linelog: Failed to open %s: %s", path, fr_syserror(errno));
                return RLM_MODULE_FAIL;
        }
 
-       if (fd >= 0) {
-               strcat(line, "\n");
+       if (inst->group != NULL) {
+               gid = strtol(inst->group, &endptr, 10);
+               if (*endptr != '\0') {
+                       if (rad_getgid(request, &gid, inst->group) < 0) {
+                               RDEBUG2("Unable to find system group \"%s\"", inst->group);
+                               goto skip_group;
+                       }
+               }
 
-               if (write(fd, line, strlen(line)) < 0) {
-                       ERROR("rlm_linelog: Failed writing: %s", fr_syserror(errno));
-                       exfile_close(inst->ef, fd);
-                       return RLM_MODULE_FAIL;
+               if (chown(path, -1, gid) == -1) {
+                       RDEBUG2("Unable to change system group of \"%s\"", path);
                }
+       }
 
-               exfile_close(inst->ef, fd);
+ skip_group:
+       strcat(line, "\n");
 
-#ifdef HAVE_SYSLOG_H
-       } else {
-               syslog(inst->syslog_priority, "%s", line);
-#endif
+       if (write(fd, line, strlen(line)) < 0) {
+               exfile_close(inst->ef, fd);
+               ERROR("rlm_linelog: Failed writing: %s", fr_syserror(errno));
+               return RLM_MODULE_FAIL;
        }
 
+       exfile_close(inst->ef, fd);
        return RLM_MODULE_OK;
 }
 
diff --git a/src/modules/rlm_mschap/README b/src/modules/rlm_mschap/README
deleted file mode 100644 (file)
index e4b473f..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-New features were added:
-+ LM support to MS-CHAP
-+ support  for  SAMBA passwd files. It introduces new files smbpass.c and
-  smbpass.h
-+ support for MS-CHAPv2. SHA1 digest support was added (sha1.c, sha1.h)
-! module is configurable via radiusd.conf and supports instances
-! 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
-  During  authentication  these  attributes  are  checked  against  data
-  provided by NAS.
-- RFC 2433 text with MS-CHAPv1 removed. Microsoft attributes are covered
-  by RFC 2458, MS-CHAPv2 - RFC 2759. You can obtain them from
-  www.rfceditor.org
-
-ZARAZA,
-3APA3A@security.nnov.ru
-
-Below is original README by Jay Miller
-
-This is a partial implementation of MS-CHAP for FreeRadius.  The patch
-was designed for Cistron-Radius 1.6.4, but the changes to source are
-pretty minimal and should work with previous versions.  It is based on
-RFC 2433, which is included with this package.
-
-I have tested this successfully using Windows 98 and Windows 2000 with Cisco 
-AS5300 terminal servers.  I have not tested it in any other environment, so 
-I can't guarantee it's success everywhere.  I also don't have time to do 
-much troubleshooting, though I am interested to hear about problems anyone
-might have.  If you can fix a problem, then I will incorporate the fix into
-the distribution.
-
-Files included:
-mschap.c        -   MS-CHAP functions
-mschap.h        -   Definitions and prototypes
-md4c.c, md4.h   -   RSA Data Security, Inc. MD4 Message-Digest Algorithm
-desport.c,
- deskey.c,
- des.h          -   Fast DES by Phil Karn (portable C version)
-rfc2433.txt     -   RFC upon which this algorithm is based
-
-
-ABOUT MS-CHAP
-
-I was driven to write this when a large customer demanded that they be
-able to check "Require Encrypted Password" in their Windows Dial-up
-Networking.  Testing showed me that, in Windows 2000 at least, this meant
-MS-CHAP.  If you want to specify CHAP, then Windows 2000 requires you to
-select "Allow unencrypted password". Duh.
-
-MS-CHAP is similar to CHAP.  The NAS creates a challenge string and gives it 
-to the client.  The client then uses the password to encrypt the challenge 
-and gives it back to the NAS, who then gives them both to Radius.  Radius
-performs the same encryption of the challenge string using the locally stored
-password, then compares the result to the response from the client.
-
-The difference between MS-CHAP and CHAP is in the encryption method.  CHAP
-performs one MD5 hash to get the response.  MS-CHAP first encrypts the password
-with MD4.  It then pads the 16-byte hash out to 21 bytes and divides this 
-string into 3 parts.  Each 7-byte part is used as a key for a DES encryption
-of the challenge string.  The 8-byte results are then concatonated together
-into a 24-byte response.
-
-The method just described is called NT-encryption by the RFC.  MS-CHAP is 
-actually designed for compatability with Microsoft LAN Manager as well.
-The response returned by the client actually contains an LM encrypted
-response as well as the NT-encrypted password.  This implementation only
-uses the NT-encrypted response, which seems to work fine for Windows 98
-and Windows 2000.  The RFC also has a number of other specs for allowing the
-user to change password and things like that.  None of that has been 
-implemented here.
-
-A useful extension of this would be in the local storage of passwords.
-Theoretically you should be able to store the MD4 hash rather than the
-plain text password.  Then the algorithm could pick it up at the next
-step and still calculate the result.  The trouble is that MD4 produces a
-binary hash.  That is, any values from 0 to 255 is a valid byte, and I
-don't know how to store this in a users file.  If it can be done, then
-we could add a check attribute called "MS-CHAP-Hash" instead of password
-and get both an encrypted protocol and encrypted password storage at the
-same time (CHAP requires plain text passwords, while Crypt-Pass requires
-an unencrypted protocol).
-
-If you find this useful, please send me a note just so I can feel good
-about myself.
-
-Jay Miller
-Columbia, MO, US
-jaymiller@socket.net
index 304eff4..4a7751a 100644 (file)
@@ -105,6 +105,10 @@ int do_auth_wbclient(rlm_mschap_t *inst, REQUEST *request,
        memcpy(authparams.password.response.challenge, challenge,
               sizeof(authparams.password.response.challenge));
 
+       authparams.parameter_control |= WBC_MSV1_0_ALLOW_MSVCHAPV2 |
+                                       WBC_MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT |
+                                       WBC_MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
+
 
        /*
         * Send auth request across to winbind
index 83ebd20..e54591c 100644 (file)
@@ -7,6 +7,11 @@ RCSIDH(auth_wbclient_h, "$Id$")
 
 #include <wbclient.h>
 
+/* Samba does not export this constant yet */
+#ifndef WBC_MSV1_0_ALLOW_MSVCHAPV2
+#define WBC_MSV1_0_ALLOW_MSVCHAPV2 0x00010000
+#endif
+
 int do_auth_wbclient(rlm_mschap_t *inst, REQUEST *request,
                     uint8_t const *challenge, uint8_t const *response,
                     uint8_t nthashhash[NT_DIGEST_LENGTH]);
index 5bd039c..83f302c 100755 (executable)
@@ -3047,7 +3047,7 @@ $as_echo "#define HAVE_MEMBERSHIP_H 1" >>confdefs.h
         mod_ldflags="-framework DirectoryService"
     fi
 
-    smart_try_dir="$winbind_include_dir"
+    smart_try_dir="$winbind_include_dir /usr/include/samba-4.0"
 
 
 ac_safe=`echo "wbclient.h" | sed 'y%./+-%__pm%'`
@@ -3286,7 +3286,247 @@ $as_echo "$as_me: WARNING: silently building without support for direct authenti
     fi
 
 
-    smart_try_dir="$winbind_lib_dir"
+
+ac_safe=`echo "core/ntstatus.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
+smart_include=
+smart_include_dir="/usr/local/include /opt/include"
+
+_smart_try_dir=
+_smart_include_dir=
+
+for _prefix in $smart_prefix ""; do
+  for _dir in $smart_try_dir; do
+    _smart_try_dir="${_smart_try_dir} ${_dir}/${_prefix}"
+  done
+
+  for _dir in $smart_include_dir; do
+    _smart_include_dir="${_smart_include_dir} ${_dir}/${_prefix}"
+  done
+done
+
+if test "x$_smart_try_dir" != "x"; then
+  for try in $_smart_try_dir; do
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for core/ntstatus.h in $try" >&5
+$as_echo_n "checking for core/ntstatus.h in $try... " >&6; }
+    CPPFLAGS="-isystem $try $old_CPPFLAGS"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdint.h>
+                                            #include <stdbool.h>
+                   #include <core/ntstatus.h>
+int
+main ()
+{
+int a = 1;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+                    smart_include="-isystem $try"
+                    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+                    break
+
+else
+
+                    smart_include=
+                    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+  CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+  for _prefix in $smart_prefix; do
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${_prefix}/core/ntstatus.h" >&5
+$as_echo_n "checking for ${_prefix}/core/ntstatus.h... " >&6; }
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdint.h>
+                                            #include <stdbool.h>
+                   #include <core/ntstatus.h>
+int
+main ()
+{
+int a = 1;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+                    smart_include="-isystem ${_prefix}/"
+                    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+                    break
+
+else
+
+                    smart_include=
+                    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+fi
+
+if test "x$smart_include" = "x"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for core/ntstatus.h" >&5
+$as_echo_n "checking for core/ntstatus.h... " >&6; }
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdint.h>
+                                            #include <stdbool.h>
+                   #include <core/ntstatus.h>
+int
+main ()
+{
+int a = 1;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+                    smart_include=" "
+                    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+                    break
+
+else
+
+                    smart_include=
+                    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+  for prefix in $smart_prefix; do
+
+
+if test "x$LOCATE" != "x"; then
+        DIRS=
+  file="${_prefix}/${1}"
+
+  for x in `${LOCATE} $file 2>/dev/null`; do
+                                        base=`echo $x | sed "s%/${file}%%"`
+    if test "x$x" = "x$base"; then
+      continue;
+    fi
+
+    dir=`${DIRNAME} $x 2>/dev/null`
+                exclude=`echo ${dir} | ${GREP} /home`
+    if test "x$exclude" != "x"; then
+      continue
+    fi
+
+                    already=`echo \$_smart_include_dir ${DIRS} | ${GREP} ${dir}`
+    if test "x$already" = "x"; then
+      DIRS="$DIRS $dir"
+    fi
+  done
+fi
+
+eval "_smart_include_dir=\"\$_smart_include_dir $DIRS\""
+
+  done
+
+
+if test "x$LOCATE" != "x"; then
+        DIRS=
+  file=core/ntstatus.h
+
+  for x in `${LOCATE} $file 2>/dev/null`; do
+                                        base=`echo $x | sed "s%/${file}%%"`
+    if test "x$x" = "x$base"; then
+      continue;
+    fi
+
+    dir=`${DIRNAME} $x 2>/dev/null`
+                exclude=`echo ${dir} | ${GREP} /home`
+    if test "x$exclude" != "x"; then
+      continue
+    fi
+
+                    already=`echo \$_smart_include_dir ${DIRS} | ${GREP} ${dir}`
+    if test "x$already" = "x"; then
+      DIRS="$DIRS $dir"
+    fi
+  done
+fi
+
+eval "_smart_include_dir=\"\$_smart_include_dir $DIRS\""
+
+
+  for try in $_smart_include_dir; do
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for core/ntstatus.h in $try" >&5
+$as_echo_n "checking for core/ntstatus.h in $try... " >&6; }
+    CPPFLAGS="-isystem $try $old_CPPFLAGS"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdint.h>
+                                            #include <stdbool.h>
+                   #include <core/ntstatus.h>
+int
+main ()
+{
+int a = 1;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+                    smart_include="-isystem $try"
+                    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+                    break
+
+else
+
+                    smart_include=
+                    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+  CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+  eval "ac_cv_header_$ac_safe=yes"
+  CPPFLAGS="$smart_include $old_CPPFLAGS"
+  SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
+fi
+
+smart_prefix=
+
+    if test "x$ac_cv_header_core_ntstatus_h" != "xyes"; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: core/ntstatus.h not found. Use --with-winbind-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: core/ntstatus.h not found. Use --with-winbind-include-dir=<path>." >&2;}
+        { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently building without support for direct authentication via winbind. requires: libwbclient" >&5
+$as_echo "$as_me: WARNING: silently building without support for direct authentication via winbind. requires: libwbclient" >&2;}
+    fi
+
+
+    if test "x$ac_cv_header_wbclient_h" = "xyes" && \
+       test "x$ac_cv_header_core_ntstatus_h" = "xyes"; then
+
+      smart_try_dir="$winbind_lib_dir"
 
 
 sm_lib_safe=`echo "wbclient" | sed 'y%./+-%__p_%'`
@@ -3461,16 +3701,17 @@ if test "x$smart_lib" != "x"; then
   SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
 fi
 
-    if test "x$ac_cv_lib_wbclient_wbcCtxAuthenticateUserEx" != "xyes"; then
-      { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: winbind libraries not found. Use --with-winbind-lib-dir=<path>." >&5
+      if test "x$ac_cv_lib_wbclient_wbcCtxAuthenticateUserEx" != "xyes"; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: winbind libraries not found. Use --with-winbind-lib-dir=<path>." >&5
 $as_echo "$as_me: WARNING: winbind libraries not found. Use --with-winbind-lib-dir=<path>." >&2;}
-      { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Samba must be version 4.2.1 or higher to use this feature." >&5
+        { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Samba must be version 4.2.1 or higher to use this feature." >&5
 $as_echo "$as_me: WARNING: Samba must be version 4.2.1 or higher to use this feature." >&2;}
-    elif test "x$ac_cv_header_wbclient_h" = "xyes"; then
-      mschap_sources="$mschap_sources auth_wbclient.c"
+      else
+        mschap_sources="$mschap_sources auth_wbclient.c"
 
 $as_echo "#define WITH_AUTH_WINBIND 1" >>confdefs.h
 
+      fi
     fi
 
     targetname=rlm_mschap
index 41b5a56..f4b40d7 100644 (file)
@@ -72,7 +72,7 @@ if test x$with_[]modname != xno; then
         mod_ldflags="-framework DirectoryService"
     fi
 
-    smart_try_dir="$winbind_include_dir"
+    smart_try_dir="$winbind_include_dir /usr/include/samba-4.0"
     FR_SMART_CHECK_INCLUDE(wbclient.h, [#include <stdint.h>
                                        #include <stdbool.h>])
     if test "x$ac_cv_header_wbclient_h" != "xyes"; then
@@ -80,18 +80,29 @@ if test x$with_[]modname != xno; then
         AC_MSG_WARN([silently building without support for direct authentication via winbind. requires: libwbclient])
     fi
 
+    FR_SMART_CHECK_INCLUDE(core/ntstatus.h, [#include <stdint.h>
+                                            #include <stdbool.h>])
+    if test "x$ac_cv_header_core_ntstatus_h" != "xyes"; then
+        AC_MSG_WARN([core/ntstatus.h not found. Use --with-winbind-include-dir=<path>.])
+        AC_MSG_WARN([silently building without support for direct authentication via winbind. requires: libwbclient])
+    fi
+
     dnl ############################################################
     dnl # Check for libraries
     dnl ############################################################
 
-    smart_try_dir="$winbind_lib_dir"
-    FR_SMART_CHECK_LIB(wbclient, wbcCtxAuthenticateUserEx)
-    if test "x$ac_cv_lib_wbclient_wbcCtxAuthenticateUserEx" != "xyes"; then
-      AC_MSG_WARN([winbind libraries not found. Use --with-winbind-lib-dir=<path>.])
-      AC_MSG_WARN([Samba must be version 4.2.1 or higher to use this feature.])
-    elif test "x$ac_cv_header_wbclient_h" = "xyes"; then
-      mschap_sources="$mschap_sources auth_wbclient.c"
-      AC_DEFINE([WITH_AUTH_WINBIND],[1],[Build with direct winbind auth support])
+    if test "x$ac_cv_header_wbclient_h" = "xyes" && \
+       test "x$ac_cv_header_core_ntstatus_h" = "xyes"; then
+
+      smart_try_dir="$winbind_lib_dir"
+      FR_SMART_CHECK_LIB(wbclient, wbcCtxAuthenticateUserEx)
+      if test "x$ac_cv_lib_wbclient_wbcCtxAuthenticateUserEx" != "xyes"; then
+        AC_MSG_WARN([winbind libraries not found. Use --with-winbind-lib-dir=<path>.])
+        AC_MSG_WARN([Samba must be version 4.2.1 or higher to use this feature.])
+      else
+        mschap_sources="$mschap_sources auth_wbclient.c"
+        AC_DEFINE([WITH_AUTH_WINBIND],[1],[Build with direct winbind auth support])
+      fi
     fi
 
     targetname=modname
index 3b17240..3509bd6 100644 (file)
@@ -1163,6 +1163,18 @@ static int CC_HINT(nonnull (1, 2, 4, 5 ,6)) do_mschap(rlm_mschap_t *inst, REQUES
                                return -648;
                        }
 
+                       if (strcasestr(buffer, "Account locked out") ||
+                           strcasestr(buffer, "0xC0000234")) {
+                               REDEBUG2("%s", buffer);
+                               return -647;
+                       }
+
+                       if (strcasestr(buffer, "Account disabled") ||
+                           strcasestr(buffer, "0xC0000072")) {
+                               REDEBUG2("%s", buffer);
+                               return -691;
+                       }
+
                        RDEBUG2("External script failed");
                        p = strchr(buffer, '\n');
                        if (p) *p = '\0';
@@ -1392,42 +1404,53 @@ static rlm_rcode_t mschap_error(rlm_mschap_t *inst, REQUEST *request, unsigned c
        char            new_challenge[33], buffer[128];
        char            *p;
 
-       if ((smb_ctrl && ((smb_ctrl->vp_integer & ACB_PW_EXPIRED) != 0)) || (mschap_result == -648)) {
+       if ((mschap_result == -648) ||
+           (smb_ctrl && ((smb_ctrl->vp_integer & ACB_PW_EXPIRED) != 0))) {
                REDEBUG("Password has expired.  User should retry authentication");
                error = 648;
-               retry = inst->allow_retry ? 1 : 0;
+
+               /*
+                *      A password change is NOT a retry!  We MUST have retry=0 here.
+                */
+               retry = 0;
                message = "Password expired";
                rcode = RLM_MODULE_REJECT;
 
-       } else if (mschap_result < 0) {
-               REDEBUG("MS-CHAP2-Response is incorrect");
-               error = 691;
-               retry = inst->allow_retry ? 1 : 0;
-               message = "Authentication failed";
-               rcode = RLM_MODULE_REJECT;
-       /*
-        *      Account is disabled.
-        *
-        *      They're found, but they don't exist, so we
-        *      return 'not found'.
-        */
-       } else if (smb_ctrl && (((smb_ctrl->vp_integer & ACB_DISABLED) != 0) ||
-                               ((smb_ctrl->vp_integer & (ACB_NORMAL|ACB_WSTRUST)) == 0))) {
-               REDEBUG("SMB-Account-Ctrl says that the account is disabled, or is not a normal "
-                       "or workstation trust account");
+               /*
+                *      Account is disabled.
+                *
+                *      They're found, but they don't exist, so we
+                *      return 'not found'.
+                */
+       } else if ((mschap_result == -691) ||
+                  (smb_ctrl && (((smb_ctrl->vp_integer & ACB_DISABLED) != 0) ||
+                                ((smb_ctrl->vp_integer & (ACB_NORMAL|ACB_WSTRUST)) == 0)))) {
+               REDEBUG("SMB-Account-Ctrl (or ntlm_auth) "
+                       "says that the account is disabled, "
+                       "or is not a normal or workstation trust account");
                error = 691;
-               retry = 1;
+               retry = 0;
                message = "Account disabled";
                rcode = RLM_MODULE_NOTFOUND;
-       /*
-        *      User is locked out.
-        */
-       } else if (smb_ctrl && ((smb_ctrl->vp_integer & ACB_AUTOLOCK) != 0)) {
-               REDEBUG("SMB-Account-Ctrl says that the account is locked out");
+
+               /*
+                *      User is locked out.
+                */
+       } else if ((mschap_result == -647) ||
+                  (smb_ctrl && ((smb_ctrl->vp_integer & ACB_AUTOLOCK) != 0))) {
+               REDEBUG("SMB-Account-Ctrl (or ntlm_auth) "
+                       "says that the account is locked out");
                error = 647;
                retry = 0;
                message = "Account locked out";
                rcode = RLM_MODULE_USERLOCK;
+
+       } else if (mschap_result < 0) {
+               REDEBUG("MS-CHAP2-Response is incorrect");
+               error = 691;
+               retry = inst->allow_retry;
+               message = "Authentication failed";
+               rcode = RLM_MODULE_REJECT;
        }
 
        if (rcode == RLM_MODULE_OK) return RLM_MODULE_OK;
@@ -1649,7 +1672,7 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *re
                 */
                uint8_t         new_nt_encrypted[516], old_nt_encrypted[NT_DIGEST_LENGTH];
                VALUE_PAIR      *nt_enc=NULL;
-               int             seq, new_nt_enc_len=0;
+               int             seq, new_nt_enc_len;
                uint8_t         *p;
 
                RDEBUG("MS-CHAPv2 password change request received");
@@ -1657,7 +1680,9 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *re
                if (cpw->vp_length != 68) {
                        REDEBUG("MS-CHAP2-CPW has the wrong format: length %zu != 68", cpw->vp_length);
                        return RLM_MODULE_INVALID;
-               } else if (cpw->vp_octets[0]!=7) {
+               }
+
+               if (cpw->vp_octets[0] != 7) {
                        REDEBUG("MS-CHAP2-CPW has the wrong format: code %d != 7", cpw->vp_octets[0]);
                        return RLM_MODULE_INVALID;
                }
@@ -1670,6 +1695,7 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *re
                 *  06:<mschapid>:00:02:<2nd chunk>
                 *  06:<mschapid>:00:03:<3rd chunk>
                 */
+               new_nt_enc_len = 0;
                for (seq = 1; seq < 4; seq++) {
                        vp_cursor_t cursor;
                        int found = 0;
@@ -1683,11 +1709,17 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *re
                                if (nt_enc->da->attr != PW_MSCHAP_NT_ENC_PW)
                                        continue;
 
+                               if (nt_enc->vp_length < 4) {
+                                       REDEBUG("MS-CHAP-NT-Enc-PW with invalid format");
+                                       return RLM_MODULE_INVALID;
+                               }
+
                                if (nt_enc->vp_octets[0] != 6) {
                                        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 ((nt_enc->vp_octets[2] == 0) && (nt_enc->vp_octets[3] == seq)) {
                                        found = 1;
                                        break;
                                }
@@ -1698,12 +1730,15 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *re
                                return RLM_MODULE_INVALID;
                        }
 
-                       /*
-                        * copy the data into the buffer
-                        */
+                       if ((new_nt_enc_len + nt_enc->vp_length - 4) > sizeof(new_nt_encrypted)) {
+                               REDEBUG("Unpacked MS-CHAP-NT-Enc-PW length > 516");
+                               return RLM_MODULE_INVALID;
+                       }
+
                        memcpy(new_nt_encrypted + new_nt_enc_len, nt_enc->vp_octets + 4, nt_enc->vp_length - 4);
                        new_nt_enc_len += nt_enc->vp_length - 4;
                }
+
                if (new_nt_enc_len != 516) {
                        REDEBUG("Unpacked MS-CHAP-NT-Enc-PW length != 516");
                        return RLM_MODULE_INVALID;
@@ -1729,7 +1764,6 @@ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *re
                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, auth_method) < 0) {
                        char buffer[128];
 
index 0e678ac..be50257 100644 (file)
@@ -273,11 +273,12 @@ redo:
 
                        old_value = vp_aprints_value(request, vp, '\'');
                        new_value = vp_aprints_value(request, new, '\'');
-                       RDEBUG3("Converted: %s = '%s' -> %s = '%s'", vp->da->name, old_value, new->da->name, new_value);
+                       RDEBUG3("Converted: &control:%s = '%s' -> &control:%s = '%s'",
+                               vp->da->name, old_value, new->da->name, new_value);
                        talloc_free(old_value);
                        talloc_free(new_value);
                } else {
-                       RDEBUG2("Converted: %s -> %s", vp->da->name, new->da->name);
+                       RDEBUG2("Converted: &control:%s -> &control:%s", vp->da->name, new->da->name);
                }
 
                return new;
@@ -538,7 +539,8 @@ static rlm_rcode_t CC_HINT(nonnull) pap_auth_clear(UNUSED rlm_pap_t *inst, REQUE
            (rad_digest_cmp(vp->vp_octets,
                            request->password->vp_octets,
                            vp->vp_length) != 0)) {
-               REDEBUG("Cleartext password does not match \"known good\" password");
+               REDEBUG("Cleartext password \"%s\" does not match \"known good\" password",
+                       request->password->vp_strvalue);
                return RLM_MODULE_REJECT;
        }
        return RLM_MODULE_OK;
index 2f9eb23..3a01ea9 100644 (file)
@@ -124,6 +124,8 @@ static const CONF_PARSER module_config[] = {
  */
 EXTERN_C void boot_DynaLoader(pTHX_ CV* cv);
 
+static int perl_sys_init3_called = 0;
+
 #ifdef USE_ITHREADS
 #  define dl_librefs "DynaLoader::dl_librefs"
 #  define dl_modules "DynaLoader::dl_modules"
@@ -272,7 +274,7 @@ static PerlInterpreter *rlm_perl_clone(PerlInterpreter *perl, pthread_key_t *key
 /*
  *     This is wrapper for radlog
  *     Now users can call radiusd::radlog(level,msg) wich is the same
- *     calling radlog from C code.
+ *     as calling radlog from C code.
  */
 static XS(XS_radiusd_radlog)
 {
@@ -527,7 +529,10 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
         *      Create tweak the server's environment to support
         *      perl. Docs say only call this once... Oops.
         */
-       PERL_SYS_INIT3(&argc, &embed, &envp);
+       if (!perl_sys_init3_called) {
+               PERL_SYS_INIT3(&argc, &embed, &envp);
+               perl_sys_init3_called = 1;
+       }
 
        /*
         *      Allocate a new perl interpreter to do the parsing
@@ -688,50 +693,50 @@ static void perl_store_vps(UNUSED TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR
  *     Value Pair Format
  *
  */
-static int pairadd_sv(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **vps, char *key, SV *sv, FR_TOKEN op,
+static void pairadd_sv(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **vps, char *key, SV *sv, FR_TOKEN op,
                      const char *hash_name, const char *list_name)
 {
-       char            *val;
+       char            *val = NULL;
        VALUE_PAIR      *vp;
+       STRLEN len;
 
-       if (SvOK(sv)) {
-               STRLEN len;
-               val = SvPV(sv, len);
-               vp = fr_pair_make(ctx, vps, key, NULL, op);
-               if (!vp) {
-               fail:
-                       REDEBUG("Failed to create pair %s:%s %s %s", list_name, key,
-                               fr_int2str(fr_tokens, op, "<INVALID>"), val);
-                       return -1;
-               }
+       VERIFY_LIST(*vps);
 
-               switch (vp->da->type) {
-               case PW_TYPE_STRING:
-                       fr_pair_value_bstrncpy(vp, val, len);
-                       break;
+       if (!SvOK(sv)) {
+       fail:
+               REDEBUG("Failed to create pair &%s:%s %s $%s{'%s'} -> '%s'", list_name, key,
+                       fr_int2str(fr_tokens, op, "<INVALID>"), hash_name, key, (val ? val : "undef"));
+               return;
+       }
+       val = SvPV(sv, len);
+       vp = fr_pair_make(ctx, vps, key, NULL, op);
+       if (!vp) goto fail;
 
-               default:
-                       if (fr_pair_value_from_str(vp, val, len) < 0) goto fail;
-               }
+       switch (vp->da->type) {
+       case PW_TYPE_STRING:
+               fr_pair_value_bstrncpy(vp, val, len);
+               break;
 
-               RDEBUG("&%s:%s %s $%s{'%s'} -> '%s'", list_name, key, fr_int2str(fr_tokens, op, "<INVALID>"),
-                      hash_name, key, val);
-               return 0;
+       default:
+               VERIFY_VP(vp);
+
+               if (fr_pair_value_from_str(vp, val, len) < 0) goto fail;
        }
-       return -1;
+
+       RDEBUG("&%s:%s %s $%s{'%s'} -> '%s'", list_name, key, fr_int2str(fr_tokens, op, "<INVALID>"),
+              hash_name, key, val);
 }
 
 /*
  *     Gets the content from hashes
  */
-static int get_hv_content(TALLOC_CTX *ctx, REQUEST *request, HV *my_hv, VALUE_PAIR **vps,
+static void get_hv_content(TALLOC_CTX *ctx, REQUEST *request, HV *my_hv, VALUE_PAIR **vps,
                          const char *hash_name, const char *list_name)
 {
        SV              *res_sv, **av_sv;
        AV              *av;
        char            *key;
        I32             key_len, len, i, j;
-       int             ret = 0;
 
        *vps = NULL;
        for (i = hv_iterinit(my_hv); i > 0; i--) {
@@ -741,12 +746,12 @@ static int get_hv_content(TALLOC_CTX *ctx, REQUEST *request, HV *my_hv, VALUE_PA
                        len = av_len(av);
                        for (j = 0; j <= len; j++) {
                                av_sv = av_fetch(av, j, 0);
-                               ret = pairadd_sv(ctx, request, vps, key, *av_sv, T_OP_ADD, hash_name, list_name) + ret;
+                               pairadd_sv(ctx, request, vps, key, *av_sv, T_OP_ADD, hash_name, list_name);
                        }
-               } else ret = pairadd_sv(ctx, request, vps, key, res_sv, T_OP_EQ, hash_name, list_name) + ret;
+               } else {
+                       pairadd_sv(ctx, request, vps, key, res_sv, T_OP_EQ, hash_name, list_name);
+               }
        }
-
-       return ret;
 }
 
 /*
@@ -810,7 +815,7 @@ static int do_perl(void *instance, REQUEST *request, char const *function_name)
                perl_store_vps(request->reply, request, &request->reply->vps, rad_reply_hv, "RAD_REPLY", "reply");
                perl_store_vps(request, request, &request->config, rad_check_hv, "RAD_CHECK", "control");
                perl_store_vps(request, request, &request->config, rad_config_hv, "RAD_CONFIG", "control");
-               perl_store_vps(request, request, &request->state, rad_state_hv, "RAD_STATE", "session-state");
+               perl_store_vps(request->state_ctx, request, &request->state, rad_state_hv, "RAD_STATE", "session-state");
 
 #ifdef WITH_PROXY
                rad_request_proxy_hv = get_hv("RAD_REQUEST_PROXY",1);
@@ -863,7 +868,8 @@ static int do_perl(void *instance, REQUEST *request, char const *function_name)
                LEAVE;
 
                vp = NULL;
-               if ((get_hv_content(request->packet, request, rad_request_hv, &vp, "RAD_REQUEST", "request")) == 0) {
+               get_hv_content(request->packet, request, rad_request_hv, &vp, "RAD_REQUEST", "request");
+               if (vp) {
                        fr_pair_list_free(&request->packet->vps);
                        request->packet->vps = vp;
                        vp = NULL;
@@ -877,39 +883,46 @@ static int do_perl(void *instance, REQUEST *request, char const *function_name)
                                request->password = fr_pair_find_by_num(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY);
                }
 
-               if ((get_hv_content(request->reply, request, rad_reply_hv, &vp, "RAD_REPLY", "reply")) == 0) {
+               get_hv_content(request->reply, request, rad_reply_hv, &vp, "RAD_REPLY", "reply");
+               if (vp) {
                        fr_pair_list_free(&request->reply->vps);
                        request->reply->vps = vp;
                        vp = NULL;
                }
 
-               if ((get_hv_content(request, request, rad_check_hv, &vp, "RAD_CHECK", "control")) == 0) {
+               get_hv_content(request, request, rad_check_hv, &vp, "RAD_CHECK", "control");
+               if (vp) {
                        fr_pair_list_free(&request->config);
                        request->config = vp;
                        vp = NULL;
                }
 
-               if ((get_hv_content(request, request, rad_state_hv, &vp, "RAD_STATE", "session-state")) == 0) {
+               get_hv_content(request->state_ctx, request, rad_state_hv, &vp, "RAD_STATE", "session-state");
+               if (vp) {
                        fr_pair_list_free(&request->state);
                        request->state = vp;
                        vp = NULL;
                }
 
 #ifdef WITH_PROXY
-               if (request->proxy &&
-                   (get_hv_content(request->proxy, request, rad_request_proxy_hv, &vp,
-                                   "RAD_REQUEST_PROXY", "proxy-request") == 0)) {
-                       fr_pair_list_free(&request->proxy->vps);
-                       request->proxy->vps = vp;
-                       vp = NULL;
+               if (request->proxy) {
+                       get_hv_content(request->proxy, request, rad_request_proxy_hv, &vp,
+                           "RAD_REQUEST_PROXY", "proxy-request");
+                       if (vp) {
+                               fr_pair_list_free(&request->proxy->vps);
+                               request->proxy->vps = vp;
+                               vp = NULL;
+                       }
                }
 
-               if (request->proxy_reply &&
-                   (get_hv_content(request->proxy_reply, request, rad_request_proxy_reply_hv, &vp,
-                                   "RAD_REQUEST_PROXY_REPLY", "proxy-reply") == 0)) {
-                       fr_pair_list_free(&request->proxy_reply->vps);
-                       request->proxy_reply->vps = vp;
-                       vp = NULL;
+               if (request->proxy_reply) {
+                       get_hv_content(request->proxy_reply, request, rad_request_proxy_reply_hv, &vp,
+                           "RAD_REQUEST_PROXY_REPLY", "proxy-reply");
+                       if (vp) {
+                               fr_pair_list_free(&request->proxy_reply->vps);
+                               request->proxy_reply->vps = vp;
+                               vp = NULL;
+                       }
                }
 #endif
 
@@ -991,12 +1004,13 @@ static int mod_detach(void *instance)
        rlm_perl_t      *inst = (rlm_perl_t *) instance;
        int             exitstatus = 0, count = 0;
 
-       if (inst->rad_perlconf_hv != NULL) hv_undef(inst->rad_perlconf_hv);
 
-       if (inst->perl_parsed && inst->func_detach) {
+       if (inst->perl_parsed) {
                dTHXa(inst->perl);
                PERL_SET_CONTEXT(inst->perl);
-               {
+               if (inst->rad_perlconf_hv != NULL) hv_undef(inst->rad_perlconf_hv);
+
+               if (inst->func_detach) {
                        dSP; ENTER; SAVETMPS;
                        PUSHMARK(SP);
 
@@ -1023,7 +1037,12 @@ static int mod_detach(void *instance)
        perl_free(inst->perl);
 #endif
 
-       PERL_SYS_TERM();
+       /*
+        *      Hope this is not really needed.
+        *      Is only allowed to be called once just before exit().
+        *
+        PERL_SYS_TERM();
+       */
        return exitstatus;
 }
 DIAG_ON(nested-externs)
index e598b8a..49b97d3 100755 (executable)
@@ -588,7 +588,7 @@ LIBOBJS
 targetname
 mod_cflags
 mod_ldflags
-PYTHONBIN
+PYTHON_BIN
 CPP
 OBJEXT
 EXEEXT
@@ -638,6 +638,7 @@ SHELL'
 ac_subst_files=''
 ac_user_opts='
 enable_option_checking
+with_rlm_python_bin
 with_rlm_python_lib_dir
 with_rlm_python_include_dir
 '
@@ -1256,6 +1257,7 @@ if test -n "$ac_init_help"; then
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-rlm-python-bin=PATH   Path to python binary
   --with-rlm-python-lib-dir=DIR       Directory for Python library files
   --with-rlm-python-include-dir=DIR   Directory for Python include files
 
@@ -2753,17 +2755,36 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
 ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 
-       for ac_prog in  python2.7 python2.6 python2.5 python2.4 python
+               PYHTON_BIN=
+
+# Check whether --with-rlm-python-bin was given.
+if test "${with_rlm_python_bin+set}" = set; then :
+  withval=$with_rlm_python_bin;  case "$withval" in
+           no)
+               as_fn_error $? "Need rlm-python-bin" "$LINENO" 5
+               ;;
+           yes)
+               ;;
+           *)
+               PYTHON_BIN="$withval"
+               ;;
+         esac
+
+fi
+
+
+       if test "x$PYTHON_BIN" = x; then
+               for ac_prog in  python2.7 python2.6 python
 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_PYTHONBIN+:} false; then :
+if ${ac_cv_prog_PYTHON_BIN+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -n "$PYTHONBIN"; then
-  ac_cv_prog_PYTHONBIN="$PYTHONBIN" # Let the user override the test.
+  if test -n "$PYTHON_BIN"; then
+  ac_cv_prog_PYTHON_BIN="$PYTHON_BIN" # Let the user override the test.
 else
 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 as_dummy="${PATH}:/usr/bin:/usr/local/bin"
@@ -2773,7 +2794,7 @@ do
   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_PYTHONBIN="$ac_prog"
+    ac_cv_prog_PYTHON_BIN="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
@@ -2783,22 +2804,23 @@ IFS=$as_save_IFS
 
 fi
 fi
-PYTHONBIN=$ac_cv_prog_PYTHONBIN
-if test -n "$PYTHONBIN"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHONBIN" >&5
-$as_echo "$PYTHONBIN" >&6; }
+PYTHON_BIN=$ac_cv_prog_PYTHON_BIN
+if test -n "$PYTHON_BIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_BIN" >&5
+$as_echo "$PYTHON_BIN" >&6; }
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
 
-  test -n "$PYTHONBIN" && break
+  test -n "$PYTHON_BIN" && break
 done
-test -n "$PYTHONBIN" || PYTHONBIN="not-found"
+test -n "$PYTHON_BIN" || PYTHON_BIN="not-found"
 
+       fi
 
-       if test x$PYTHONBIN = xnot-found; then
+       if test "x$PYTHON_BIN" = "xnot-found"; then
                fail="python-binary"
        fi
 
@@ -2839,25 +2861,41 @@ fi
 
 
        if test x$fail = x; then
+               PY_PREFIX=`${PYTHON_BIN} -c 'import sys ; print(sys.prefix)'`
+               { $as_echo "$as_me:${as_lineno-$LINENO}: Python sys.prefix \"${PY_PREFIX}\"" >&5
+$as_echo "$as_me: Python sys.prefix \"${PY_PREFIX}\"" >&6;}
+
+               PY_EXEC_PREFIX=`${PYTHON_BIN} -c 'import sys ; print(sys.exec_prefix)'`
+               { $as_echo "$as_me:${as_lineno-$LINENO}: Python sys.exec_prefix \"${PY_EXEC_PREFIX}\"" >&5
+$as_echo "$as_me: Python sys.exec_prefix \"${PY_EXEC_PREFIX}\"" >&6;}
+
+               PY_SYS_VERSION=`${PYTHON_BIN} -c 'import sys ; print(sys.version[0:3])'`
+               { $as_echo "$as_me:${as_lineno-$LINENO}: Python sys.version \"${PY_SYS_VERSION}\"" >&5
+$as_echo "$as_me: Python sys.version \"${PY_SYS_VERSION}\"" >&6;}
+
+               PY_LIB_DIR="$PY_EXEC_PREFIX/lib/python${PY_SYS_VERSION}/config"
+               PY_LIB_LOC="-L$PY_EXEC_PREFIX/lib/python${PY_SYS_VERSION}/config"
 
-               PY_PREFIX=`${PYTHONBIN} -c 'import sys ; print(sys.prefix)'`
-               PY_EXEC_PREFIX=`${PYTHONBIN} -c 'import sys ; print(sys.exec_prefix)'`
-                               PY_VERSION=`${PYTHONBIN} -c 'import sys ; print(sys.version[0:3])'`
-                               PY_LIBS="-lpython$PY_VERSION"
-               PY_LIB_DIR="$PY_EXEC_PREFIX/lib/python$PY_VERSION/config"
-               PY_LIB_LOC="-L$PY_EXEC_PREFIX/lib/python$PY_VERSION/config"
-               PY_MAKEFILE="$PY_EXEC_PREFIX/lib/python$PY_VERSION/config/Makefile"
+               PY_MAKEFILE="$PY_EXEC_PREFIX/lib/python${PY_SYS_VERSION}/config/Makefile"
                if test -f ${PY_MAKEFILE}; then
-                       PY_LOCALMODLIBS=`sed -n -e 's/^LOCALMODLIBS=\(.*\)/\1/p' $PY_MAKEFILE`
-                       PY_BASEMODLIBS=`sed -n -e 's/^BASEMODLIBS=\(.*\)/\1/p' $PY_MAKEFILE`
-                       PY_OTHER_LIBS=`sed -n -e 's/^LIBS=\(.*\)/\1/p' $PY_MAKEFILE`
-                       PY_OTHER_LDFLAGS=`sed -n -e 's/^LINKFORSHARED=\(.*\)/\1/p' $PY_MAKEFILE`
+                       PY_LOCAL_MOD_LIBS=`sed -n -e 's/^LOCALMODLIBS=\(.*\)/\1/p' $PY_MAKEFILE | sed -e 's/[[:blank:]]/ /g;s/^ *//;s/ *$//'`
+                       { $as_echo "$as_me:${as_lineno-$LINENO}: Python local_mod_libs \"${PY_LOCAL_MOD_LIBS}\"" >&5
+$as_echo "$as_me: Python local_mod_libs \"${PY_LOCAL_MOD_LIBS}\"" >&6;}
+
+                       PY_BASE_MOD_LIBS=`sed -n -e 's/^BASEMODLIBS=\(.*\)/\1/p' $PY_MAKEFILE | sed -e 's/[[:blank:]]/ /g;s/^ *//;s/ *$//'`
+                       { $as_echo "$as_me:${as_lineno-$LINENO}: Python base_mod_libs \"${PY_BASE_MOD_LIBS}\"" >&5
+$as_echo "$as_me: Python base_mod_libs \"${PY_BASE_MOD_LIBS}\"" >&6;}
+
+                       PY_OTHER_LIBS=`sed -n -e 's/^LIBS=\(.*\)/\1/p' $PY_MAKEFILE | sed -e 's/[[:blank:]]/ /g;s/  / /g;s/^ *//;s/ *$//'`
+                       PY_OTHER_LDFLAGS=`sed -n -e 's/^LINKFORSHARED=\(.*\)/\1/p' $PY_MAKEFILE | sed -e 's/[[:blank:]]/ /g;s/  / /g;s/^ *//;s/ *$//'`
+                       { $as_echo "$as_me:${as_lineno-$LINENO}: Python other_libs \"${PY_OTHER_LDFLAGS} ${PY_OTHER_LIBS}\"" >&5
+$as_echo "$as_me: Python other_libs \"${PY_OTHER_LDFLAGS} ${PY_OTHER_LIBS}\"" >&6;}
                fi
-               PY_EXTRA_LIBS="$PY_LOCALMODLIBS $PY_BASEMODLIBS $PY_OTHER_LIBS"
+               PY_EXTRA_LIBS="$PY_LOCALMODLIBS $PY_BASE_MOD_LIBS $PY_OTHER_LIBS"
 
                old_CFLAGS=$CFLAGS
                CFLAGS="$CFLAGS $PY_CFLAGS"
-               smart_try_dir="$PY_PREFIX/include/python$PY_VERSION"
+               smart_try_dir="$PY_PREFIX/include/python$PY_SYS_VERSION"
 
 
 
@@ -3099,7 +3137,7 @@ smart_prefix=
                smart_try_dir=$PY_LIB_DIR
 
 
-sm_lib_safe=`echo "python${PY_VERSION}" | sed 'y%./+-%__p_%'`
+sm_lib_safe=`echo "python${PY_SYS_VERSION}" | sed 'y%./+-%__p_%'`
 sm_func_safe=`echo "Py_Initialize" | sed 'y%./+-%__p_%'`
 
 old_LIBS="$LIBS"
@@ -3110,9 +3148,9 @@ 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="-lpython${PY_VERSION} $old_LIBS"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Py_Initialize in -lpython${PY_SYS_VERSION} in $try" >&5
+$as_echo_n "checking for Py_Initialize in -lpython${PY_SYS_VERSION} in $try... " >&6; }
+    LIBS="-lpython${PY_SYS_VERSION} $old_LIBS"
     CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
@@ -3127,7 +3165,7 @@ Py_Initialize()
 _ACEOF
 if ac_fn_c_try_link "$LINENO"; then :
 
-                smart_lib="-lpython${PY_VERSION}"
+                smart_lib="-lpython${PY_SYS_VERSION}"
                 smart_ldflags="-L$try -Wl,-rpath,$try"
                 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
@@ -3145,9 +3183,9 @@ rm -f core conftest.err conftest.$ac_objext \
 fi
 
 if test "x$smart_lib" = "x"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Py_Initialize in -lpython${PY_VERSION}" >&5
-$as_echo_n "checking for Py_Initialize in -lpython${PY_VERSION}... " >&6; }
-  LIBS="-lpython${PY_VERSION} $old_LIBS"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Py_Initialize in -lpython${PY_SYS_VERSION}" >&5
+$as_echo_n "checking for Py_Initialize in -lpython${PY_SYS_VERSION}... " >&6; }
+  LIBS="-lpython${PY_SYS_VERSION} $old_LIBS"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 extern char Py_Initialize();
@@ -3161,7 +3199,7 @@ Py_Initialize()
 _ACEOF
 if ac_fn_c_try_link "$LINENO"; then :
 
-               smart_lib="-lpython${PY_VERSION}"
+               smart_lib="-lpython${PY_SYS_VERSION}"
                { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
 
@@ -3179,7 +3217,7 @@ if test "x$smart_lib" = "x"; then
 
 if test "x$LOCATE" != "x"; then
         DIRS=
-  file=libpython${PY_VERSION}${libltdl_cv_shlibext}
+  file=libpython${PY_SYS_VERSION}${libltdl_cv_shlibext}
 
   for x in `${LOCATE} $file 2>/dev/null`; do
                                         base=`echo $x | sed "s%/${file}%%"`
@@ -3206,7 +3244,7 @@ eval "smart_lib_dir=\"\$smart_lib_dir $DIRS\""
 
 if test "x$LOCATE" != "x"; then
         DIRS=
-  file=libpython${PY_VERSION}.a
+  file=libpython${PY_SYS_VERSION}.a
 
   for x in `${LOCATE} $file 2>/dev/null`; do
                                         base=`echo $x | sed "s%/${file}%%"`
@@ -3231,9 +3269,9 @@ 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 Py_Initialize in -lpython${PY_VERSION} in $try" >&5
-$as_echo_n "checking for Py_Initialize in -lpython${PY_VERSION} in $try... " >&6; }
-    LIBS="-lpython${PY_VERSION} $old_LIBS"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Py_Initialize in -lpython${PY_SYS_VERSION} in $try" >&5
+$as_echo_n "checking for Py_Initialize in -lpython${PY_SYS_VERSION} in $try... " >&6; }
+    LIBS="-lpython${PY_SYS_VERSION} $old_LIBS"
     CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
@@ -3248,7 +3286,7 @@ Py_Initialize()
 _ACEOF
 if ac_fn_c_try_link "$LINENO"; then :
 
-                 smart_lib="-lpython${PY_VERSION}"
+                 smart_lib="-lpython${PY_SYS_VERSION}"
                  smart_ldflags="-L$try -Wl,-rpath,$try"
                  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
@@ -3280,7 +3318,7 @@ fi
                else
 
 
-sm_lib_safe=`echo "python${PY_VERSION}m" | sed 'y%./+-%__p_%'`
+sm_lib_safe=`echo "python${PY_SYS_VERSION}m" | sed 'y%./+-%__p_%'`
 sm_func_safe=`echo "Py_Initialize" | sed 'y%./+-%__p_%'`
 
 old_LIBS="$LIBS"
@@ -3291,9 +3329,9 @@ 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="-lpython${PY_VERSION}m $old_LIBS"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Py_Initialize in -lpython${PY_SYS_VERSION}m in $try" >&5
+$as_echo_n "checking for Py_Initialize in -lpython${PY_SYS_VERSION}m in $try... " >&6; }
+    LIBS="-lpython${PY_SYS_VERSION}m $old_LIBS"
     CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
@@ -3308,7 +3346,7 @@ Py_Initialize()
 _ACEOF
 if ac_fn_c_try_link "$LINENO"; then :
 
-                smart_lib="-lpython${PY_VERSION}m"
+                smart_lib="-lpython${PY_SYS_VERSION}m"
                 smart_ldflags="-L$try -Wl,-rpath,$try"
                 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
@@ -3326,9 +3364,9 @@ rm -f core conftest.err conftest.$ac_objext \
 fi
 
 if test "x$smart_lib" = "x"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Py_Initialize in -lpython${PY_VERSION}m" >&5
-$as_echo_n "checking for Py_Initialize in -lpython${PY_VERSION}m... " >&6; }
-  LIBS="-lpython${PY_VERSION}m $old_LIBS"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Py_Initialize in -lpython${PY_SYS_VERSION}m" >&5
+$as_echo_n "checking for Py_Initialize in -lpython${PY_SYS_VERSION}m... " >&6; }
+  LIBS="-lpython${PY_SYS_VERSION}m $old_LIBS"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 extern char Py_Initialize();
@@ -3342,7 +3380,7 @@ Py_Initialize()
 _ACEOF
 if ac_fn_c_try_link "$LINENO"; then :
 
-               smart_lib="-lpython${PY_VERSION}m"
+               smart_lib="-lpython${PY_SYS_VERSION}m"
                { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
 
@@ -3360,7 +3398,7 @@ if test "x$smart_lib" = "x"; then
 
 if test "x$LOCATE" != "x"; then
         DIRS=
-  file=libpython${PY_VERSION}m${libltdl_cv_shlibext}
+  file=libpython${PY_SYS_VERSION}m${libltdl_cv_shlibext}
 
   for x in `${LOCATE} $file 2>/dev/null`; do
                                         base=`echo $x | sed "s%/${file}%%"`
@@ -3387,7 +3425,7 @@ eval "smart_lib_dir=\"\$smart_lib_dir $DIRS\""
 
 if test "x$LOCATE" != "x"; then
         DIRS=
-  file=libpython${PY_VERSION}m.a
+  file=libpython${PY_SYS_VERSION}m.a
 
   for x in `${LOCATE} $file 2>/dev/null`; do
                                         base=`echo $x | sed "s%/${file}%%"`
@@ -3412,9 +3450,9 @@ 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 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="-lpython${PY_VERSION}m $old_LIBS"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Py_Initialize in -lpython${PY_SYS_VERSION}m in $try" >&5
+$as_echo_n "checking for Py_Initialize in -lpython${PY_SYS_VERSION}m in $try... " >&6; }
+    LIBS="-lpython${PY_SYS_VERSION}m $old_LIBS"
     CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
@@ -3429,7 +3467,7 @@ Py_Initialize()
 _ACEOF
 if ac_fn_c_try_link "$LINENO"; then :
 
-                 smart_lib="-lpython${PY_VERSION}m"
+                 smart_lib="-lpython${PY_SYS_VERSION}m"
                  smart_ldflags="-L$try -Wl,-rpath,$try"
                  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
@@ -3458,7 +3496,7 @@ fi
                                targetname=rlm_python
                        else
                                targetname=
-                               fail="$fail libpython$PY_VERSION"
+                               fail="$fail libpython$PY_SYS_VERSION"
                        fi
                fi
        fi
index 58b2d80..831a33a 100644 (file)
@@ -8,9 +8,27 @@ if test x$with_[]modname != xno; then
        AC_PROG_CC
        AC_PROG_CPP
 
-       AC_CHECK_PROGS(PYTHONBIN, [ python2.7 python2.6 python2.5 python2.4 python ], not-found, [${PATH}:/usr/bin:/usr/local/bin])
+       dnl extra argument: --with-rlm-python-bin
+       PYHTON_BIN=
+       AC_ARG_WITH(rlm-python-bin,
+       [  --with-rlm-python-bin=PATH   Path to python binary []],
+       [ case "$withval" in
+           no)
+               AC_MSG_ERROR(Need rlm-python-bin)
+               ;;
+           yes)
+               ;;
+           *)
+               PYTHON_BIN="$withval"
+               ;;
+         esac ]
+       )
+
+       if test "x$PYTHON_BIN" = x; then
+               AC_CHECK_PROGS(PYTHON_BIN, [ python2.7 python2.6 python ], not-found, [${PATH}:/usr/bin:/usr/local/bin])
+       fi
 
-       if test x$PYTHONBIN = xnot-found; then
+       if test "x$PYTHON_BIN" = "xnot-found"; then
                fail="python-binary"
        fi
 
@@ -47,27 +65,35 @@ if test x$with_[]modname != xno; then
        )
 
        if test x$fail = x; then
+               PY_PREFIX=`${PYTHON_BIN} -c 'import sys ; print(sys.prefix)'`
+               AC_MSG_NOTICE([Python sys.prefix \"${PY_PREFIX}\"])
+
+               PY_EXEC_PREFIX=`${PYTHON_BIN} -c 'import sys ; print(sys.exec_prefix)'`
+               AC_MSG_NOTICE([Python sys.exec_prefix \"${PY_EXEC_PREFIX}\"])
 
-               PY_PREFIX=`${PYTHONBIN} -c 'import sys ; print(sys.prefix)'`
-               PY_EXEC_PREFIX=`${PYTHONBIN} -c 'import sys ; print(sys.exec_prefix)'`
-               changequote(<<, >>)dnl
-               PY_VERSION=`${PYTHONBIN} -c 'import sys ; print(sys.version[0:3])'`
-               changequote([, ])dnl
-               PY_LIBS="-lpython$PY_VERSION"
-               PY_LIB_DIR="$PY_EXEC_PREFIX/lib/python$PY_VERSION/config"
-               PY_LIB_LOC="-L$PY_EXEC_PREFIX/lib/python$PY_VERSION/config"
-               PY_MAKEFILE="$PY_EXEC_PREFIX/lib/python$PY_VERSION/config/Makefile"
+               PY_SYS_VERSION=`${PYTHON_BIN} -c 'import sys ; print(sys.version[[0:3]])'`
+               AC_MSG_NOTICE([Python sys.version \"${PY_SYS_VERSION}\"])
+
+               PY_LIB_DIR="$PY_EXEC_PREFIX/lib/python${PY_SYS_VERSION}/config"
+               PY_LIB_LOC="-L$PY_EXEC_PREFIX/lib/python${PY_SYS_VERSION}/config"
+
+               PY_MAKEFILE="$PY_EXEC_PREFIX/lib/python${PY_SYS_VERSION}/config/Makefile"
                if test -f ${PY_MAKEFILE}; then
-                       PY_LOCALMODLIBS=`sed -n -e 's/^LOCALMODLIBS=\(.*\)/\1/p' $PY_MAKEFILE`
-                       PY_BASEMODLIBS=`sed -n -e 's/^BASEMODLIBS=\(.*\)/\1/p' $PY_MAKEFILE`
-                       PY_OTHER_LIBS=`sed -n -e 's/^LIBS=\(.*\)/\1/p' $PY_MAKEFILE`
-                       PY_OTHER_LDFLAGS=`sed -n -e 's/^LINKFORSHARED=\(.*\)/\1/p' $PY_MAKEFILE`
+                       PY_LOCAL_MOD_LIBS=`sed -n -e 's/^LOCALMODLIBS=\(.*\)/\1/p' $PY_MAKEFILE | sed -e 's/[[[:blank:]]]/ /g;s/^ *//;s/ *$//'`
+                       AC_MSG_NOTICE([Python local_mod_libs \"${PY_LOCAL_MOD_LIBS}\"])
+
+                       PY_BASE_MOD_LIBS=`sed -n -e 's/^BASEMODLIBS=\(.*\)/\1/p' $PY_MAKEFILE | sed -e 's/[[[:blank:]]]/ /g;s/^ *//;s/ *$//'`
+                       AC_MSG_NOTICE([Python base_mod_libs \"${PY_BASE_MOD_LIBS}\"])
+
+                       PY_OTHER_LIBS=`sed -n -e 's/^LIBS=\(.*\)/\1/p' $PY_MAKEFILE | sed -e 's/[[[:blank:]]]/ /g;s/  / /g;s/^ *//;s/ *$//'`
+                       PY_OTHER_LDFLAGS=`sed -n -e 's/^LINKFORSHARED=\(.*\)/\1/p' $PY_MAKEFILE | sed -e 's/[[[:blank:]]]/ /g;s/  / /g;s/^ *//;s/ *$//'`
+                       AC_MSG_NOTICE([Python other_libs \"${PY_OTHER_LDFLAGS} ${PY_OTHER_LIBS}\"])
                fi
-               PY_EXTRA_LIBS="$PY_LOCALMODLIBS $PY_BASEMODLIBS $PY_OTHER_LIBS"
+               PY_EXTRA_LIBS="$PY_LOCALMODLIBS $PY_BASE_MOD_LIBS $PY_OTHER_LIBS"
 
                old_CFLAGS=$CFLAGS
                CFLAGS="$CFLAGS $PY_CFLAGS"
-               smart_try_dir="$PY_PREFIX/include/python$PY_VERSION"
+               smart_try_dir="$PY_PREFIX/include/python$PY_SYS_VERSION"
                FR_SMART_CHECK_INCLUDE(Python.h)
                CFLAGS=$old_CFLAGS
 
@@ -81,7 +107,7 @@ if test x$with_[]modname != xno; then
                old_LIBS=$LIBS
                LIBS="$LIBS $PY_LIB_LOC $PY_EXTRA_LIBS -lm"
                smart_try_dir=$PY_LIB_DIR
-               FR_SMART_CHECK_LIB(python${PY_VERSION}, Py_Initialize)
+               FR_SMART_CHECK_LIB(python${PY_SYS_VERSION}, Py_Initialize)
                LIBS=$old_LIBS
 
                eval t=\${ac_cv_lib_${sm_lib_safe}_${sm_func_safe}}
@@ -89,14 +115,14 @@ if test x$with_[]modname != xno; then
                        mod_ldflags="$PY_LIB_LOC $PY_EXTRA_LIBS $SMART_LIBS -lm"
                        targetname=modname
                else
-                       FR_SMART_CHECK_LIB(python${PY_VERSION}m, Py_Initialize)
+                       FR_SMART_CHECK_LIB(python${PY_SYS_VERSION}m, Py_Initialize)
                        eval t=\${ac_cv_lib_${sm_lib_safe}_${sm_func_safe}}
                        if test "x$t" = "xyes"; then
                                mod_ldflags="$PY_LIB_LOC $PY_EXTRA_LIBS $SMART_LIBS -lm"
                                targetname=modname
                        else
                                targetname=
-                               fail="$fail libpython$PY_VERSION"
+                               fail="$fail libpython$PY_SYS_VERSION"
                        fi
                fi
        fi
index dd5b0b8..5950a07 100644 (file)
@@ -10,6 +10,7 @@ import radiusd
 def instantiate(p):
   print "*** instantiate ***"
   print p
+  # return 0 for success or -1 for failure
 
 def authorize(p):
   print "*** authorize ***"
@@ -17,6 +18,9 @@ def authorize(p):
   radiusd.radlog(radiusd.L_INFO, '*** radlog call in authorize ***')
   print
   print p
+  print
+  print radiusd.config
+  print
   return radiusd.RLM_MODULE_OK
 
 def preacct(p):
index f8fb7c8..c3cbf57 100644 (file)
@@ -161,15 +161,14 @@ def authorize(authData):
   # If you want to use different operators
   # you can do
   # return (radiusd.RLM_MODULE_UPDATED,
-  #         radiusd.resolve(
-  #            'Session-Timeout := %s' % str(sessionTimeout),
-  #            'Some-other-option -= Value',
+  #         (
+  #            ('Session-Timeout', ':=', str(sessionTimeout)),
+  #            ('Some-other-option', '-=', Value'),
+  #         ),
+  #         (
+  #            ('Auth-Type', ':=', 'python'),
   #         ),
-  #         radiusd.resolve(
-  #            'Auth-Type := python'
-  #         )
   #        )
-  # Edit operators you need in OP_TRY in radiusd.py
 
 def authenticate(p):
   p = p
index 40247b3..e12bbd6 100644 (file)
@@ -32,22 +32,6 @@ 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
index 22456a0..381e686 100644 (file)
  *
  * @note Rewritten by Paul P. Komkoff Jr <i@stingr.net>.
  *
- * @copyright 2000,2006  The FreeRADIUS server project
+ * @copyright 2000,2006,2015-2016  The FreeRADIUS server project
  * @copyright 2002  Miguel A.L. Paraz <mparaz@mparaz.com>
  * @copyright 2002  Imperium Technology, Inc.
  */
 RCSID("$Id$")
 
+#define LOG_PREFIX "rlm_python - "
+
 #include <freeradius-devel/radiusd.h>
 #include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
 
 #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
+static uint32_t                python_instances = 0;
+static void            *python_dlhandle;
 
-/*
- *     TODO: The only needed thing here is function. Anything else is
- *     required for initialization only. I will remove it, putting a
- *     symbolic constant here instead.
+static PyThreadState   *main_interpreter;      //!< Main interpreter (cext safe)
+static PyObject                *main_module;           //!< Pthon configuration dictionary.
+
+/** Specifies the module.function to load for processing a section
+ *
  */
-struct py_function_def {
-       PyObject        *module;
-       PyObject        *function;
+typedef struct python_func_def {
+       PyObject        *module;                //!< Python reference to module.
+       PyObject        *function;              //!< Python reference to function in module.
 
-       char const      *module_name;
-       char const      *function_name;
-};
+       char const      *module_name;           //!< String name of module.
+       char const      *function_name;         //!< String name of function in module.
+} python_func_def_t;
 
+/** An instance of the rlm_python module
+ *
+ */
 typedef struct rlm_python_t {
-       void            *libpython;
-       PyThreadState   *main_thread_state;
-       char const      *python_path;
-
-       struct py_function_def
+       char const      *name;                  //!< Name of the module instance
+       PyThreadState   *sub_interpreter;       //!< The main interpreter/thread used for this instance.
+       char const      *python_path;           //!< Path to search for python files in.
+       PyObject        *module;                //!< Local, interpreter specific module, containing
+                                               //!< FreeRADIUS functions.
+       bool            cext_compat;            //!< Whether or not to create sub-interpreters per module
+                                               //!< instance.
+
+       python_func_def_t
        instantiate,
        authorize,
        authenticate,
@@ -74,14 +80,27 @@ typedef struct rlm_python_t {
        send_coa,
 #endif
        detach;
+
+       PyObject        *pythonconf_dict;       //!< Configuration parameters defined in the module
+                                               //!< made available to the python script.
 } rlm_python_t;
 
+/** Tracks a python module inst/thread state pair
+ *
+ * Multiple instances of python create multiple interpreters and each
+ * thread must have a PyThreadState per interpreter, to track execution.
+ */
+typedef struct python_thread_state {
+       PyThreadState           *state;         //!< Module instance/thread specific state.
+       rlm_python_t            *inst;          //!< Module instance that created this thread state.
+} python_thread_state_t;
+
 /*
  *     A mapping of configuration file names to internal variables.
  */
 static CONF_PARSER module_config[] = {
 
-#define A(x) { "mod_" #x, FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, x.module_name), NULL }, \
+#define A(x) { "mod_" #x, FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, x.module_name), "${.module}" }, \
        { "func_" #x, FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, x.function_name), NULL },
 
        A(instantiate)
@@ -102,6 +121,8 @@ static CONF_PARSER module_config[] = {
 #undef A
 
        { "python_path", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, python_path), NULL },
+       { "cext_compat", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_python_t, cext_compat), "yes" },
+
        CONF_PARSER_TERMINATOR
 };
 
@@ -113,10 +134,17 @@ static struct {
 #define A(x) { #x, x },
 
        A(L_DBG)
+       A(L_WARN)
        A(L_AUTH)
        A(L_INFO)
        A(L_ERR)
        A(L_PROXY)
+       A(L_WARN)
+       A(L_ACCT)
+       A(L_DBG_WARN)
+       A(L_DBG_ERR)
+       A(L_DBG_WARN_REQ)
+       A(L_DBG_ERR_REQ)
        A(RLM_MODULE_REJECT)
        A(RLM_MODULE_FAIL)
        A(RLM_MODULE_OK)
@@ -136,21 +164,15 @@ static struct {
 /*
  *     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
- *     one intepreter
- */
-
-static PyObject *radiusd_module = NULL;
+fr_thread_local_setup(rbtree_t *, local_thread_state)  /* macro */
 
 /*
  *     radiusd Python functions
  */
 
-/* radlog wrapper */
+/** Allow radlog to be called from python
+ *
+ */
 static PyObject *mod_radlog(UNUSED PyObject *module, PyObject *args)
 {
        int status;
@@ -166,7 +188,7 @@ static PyObject *mod_radlog(UNUSED PyObject *module, PyObject *args)
        return Py_None;
 }
 
-static PyMethodDef radiusd_methods[] = {
+static PyMethodDef module_methods[] = {
        { "radlog", &mod_radlog, METH_VARARGS,
          "radiusd.radlog(level, msg)\n\n" \
          "Print a message using radiusd logging system. level should be one of the\n" \
@@ -175,13 +197,14 @@ static PyMethodDef radiusd_methods[] = {
        { NULL, NULL, 0, NULL },
 };
 
-
-static void mod_error(void)
+/** Print out the current error
+ *
+ * Must be called with a valid thread state set
+ */
+static void python_error_log(void)
 {
        PyObject *pType = NULL, *pValue = NULL, *pTraceback = NULL, *pStr1 = NULL, *pStr2 = NULL;
 
-       /* This will be called with the GIL lock held */
-
        PyErr_Fetch(&pType, &pValue, &pTraceback);
        if (!pType || !pValue)
                goto failed;
@@ -189,7 +212,7 @@ static void mod_error(void)
            ((pStr2 = PyObject_Str(pValue)) == NULL))
                goto failed;
 
-       ERROR("rlm_python:EXCEPT:%s: %s", PyString_AsString(pStr1), PyString_AsString(pStr2));
+       ERROR("%s (%s)", PyString_AsString(pStr1), PyString_AsString(pStr2));
 
 failed:
        Py_XDECREF(pStr1);
@@ -199,155 +222,110 @@ failed:
        Py_XDECREF(pTraceback);
 }
 
-static int mod_init(rlm_python_t *inst)
-{
-       int i;
-       static char name[] = "radiusd";
-
-       if (radiusd_module) return 0;
-
-       /*
-        *      Explicitly load libpython, so symbols will be available to lib-dynload modules
-        */
-       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)
-               goto failed;
-
-       for (i = 0; radiusd_constants[i].name; i++) {
-               if ((PyModule_AddIntConstant(radiusd_module, radiusd_constants[i].name,
-                                            radiusd_constants[i].value)) < 0) {
-                       goto failed;
-               }
-       }
-
-#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:
-       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;
-}
-
-#if 0
-
-static int mod_destroy(void)
-{
-       Pyx_BLOCK_THREADS
-       Py_XDECREF(radiusd_module);
-       Py_Finalize();
-       Pyx_UNBLOCK_THREADS
-
-       return 0;
-}
-
-/*
- *     This will need reconsidering in a future. Maybe we'll need to
- *     have our own reference counting for radiusd_module
- */
-#endif
-
-/* TODO: Convert this function to accept any iterable objects? */
-
-static void mod_vptuple(TALLOC_CTX *ctx, VALUE_PAIR **vps, PyObject *pValue,
-                       char const *funcname)
+static void mod_vptuple(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **vps, PyObject *pValue,
+                       char const *funcname, char const *list_name)
 {
        int          i;
        int          tuplesize;
+       vp_tmpl_t       dst;
        VALUE_PAIR      *vp;
+       REQUEST         *current = request;
+
+       memset(&dst, 0, sizeof(dst));
 
        /*
         *      If the Python function gave us None for the tuple,
         *      then just return.
         */
-       if (pValue == Py_None)
-               return;
+       if (pValue == Py_None) return;
 
        if (!PyTuple_CheckExact(pValue)) {
-               ERROR("rlm_python:%s: non-tuple passed", funcname);
+               ERROR("%s - non-tuple passed to %s", funcname, list_name);
                return;
        }
        /* Get the tuple tuplesize. */
        tuplesize = PyTuple_GET_SIZE(pValue);
        for (i = 0; i < tuplesize; i++) {
-               PyObject *pTupleElement = PyTuple_GET_ITEM(pValue, i);
-               PyObject *pStr1;
-               PyObject *pStr2;
-               PyObject *pOp;
-               int pairsize;
-               char const *s1;
-               char const *s2;
-               long op;
+               PyObject        *pTupleElement = PyTuple_GET_ITEM(pValue, i);
+               PyObject        *pStr1;
+               PyObject        *pStr2;
+               PyObject        *pOp;
+               int             pairsize;
+               char const      *s1;
+               char const      *s2;
+               FR_TOKEN        op = T_OP_EQ;
 
                if (!PyTuple_CheckExact(pTupleElement)) {
-                       ERROR("rlm_python:%s: tuple element %d is not a tuple", funcname, i);
+                       ERROR("%s - Tuple element %d of %s is not a tuple", funcname, i, list_name);
                        continue;
                }
                /* Check if it's a pair */
 
                pairsize = PyTuple_GET_SIZE(pTupleElement);
                if ((pairsize < 2) || (pairsize > 3)) {
-                       ERROR("rlm_python:%s: tuple element %d is a tuple of size %d. Must be 2 or 3.", funcname, i, pairsize);
+                       ERROR("%s - Tuple element %d of %s is a tuple of size %d. Must be 2 or 3",
+                             funcname, i, list_name, pairsize);
                        continue;
                }
 
-               if (pairsize == 2) {
-                       pStr1   = PyTuple_GET_ITEM(pTupleElement, 0);
-                       pStr2   = PyTuple_GET_ITEM(pTupleElement, 1);
-                       op      = T_OP_EQ;
-               } else {
-                       pStr1   = PyTuple_GET_ITEM(pTupleElement, 0);
-                       pStr2   = PyTuple_GET_ITEM(pTupleElement, 2);
-                       pOp     = PyTuple_GET_ITEM(pTupleElement, 1);
-                       op      = PyInt_AsLong(pOp);
-               }
+               pStr1 = PyTuple_GET_ITEM(pTupleElement, 0);
+               pStr2 = PyTuple_GET_ITEM(pTupleElement, pairsize-1);
 
                if ((!PyString_CheckExact(pStr1)) || (!PyString_CheckExact(pStr2))) {
-                       ERROR("rlm_python:%s: tuple element %d must be as (str, str)", funcname, i);
+                       ERROR("%s - Tuple element %d of %s must be as (str, str)",
+                             funcname, i, list_name);
                        continue;
                }
                s1 = PyString_AsString(pStr1);
                s2 = PyString_AsString(pStr2);
-               vp = fr_pair_make(ctx, vps, s1, s2, op);
-               if (vp != NULL) {
-                       DEBUG("rlm_python:%s: '%s' = '%s'", funcname, s1, s2);
+
+               if (pairsize == 3) {
+                       pOp = PyTuple_GET_ITEM(pTupleElement, 1);
+                       if (PyString_CheckExact(pOp)) {
+                               if (!(op = fr_str2int(fr_tokens, PyString_AsString(pOp), 0))) {
+                                       ERROR("%s - Invalid operator %s:%s %s %s, falling back to '='",
+                                             funcname, list_name, s1, PyString_AsString(pOp), s2);
+                                       op = T_OP_EQ;
+                               }
+                       } else if (PyInt_Check(pOp)) {
+                               op      = PyInt_AsLong(pOp);
+                               if (!fr_int2str(fr_tokens, op, NULL)) {
+                                       ERROR("%s - Invalid operator %s:%s %i %s, falling back to '='",
+                                             funcname, list_name, s1, op, s2);
+                                       op = T_OP_EQ;
+                               }
+                       } else {
+                               ERROR("%s - Invalid operator type for %s:%s ? %s, using default '='",
+                                     funcname, list_name, s1, s2);
+                       }
+               }
+
+               if (tmpl_from_attr_str(&dst, s1, REQUEST_CURRENT, PAIR_LIST_REPLY, false, false) <= 0) {
+                       ERROR("%s - Failed to find attribute %s:%s", funcname, list_name, s1);
+                       continue;
+               }
+
+               if (radius_request(&current, dst.tmpl_request) < 0) {
+                       ERROR("%s - Attribute name %s:%s refers to outer request but not in a tunnel, skipping...",
+                             funcname, list_name, s1);
+                       continue;
+               }
+
+               if (!(vp = fr_pair_afrom_da(ctx, dst.tmpl_da))) {
+                       ERROR("%s - Failed to create attribute %s:%s", funcname, list_name, s1);
+                       continue;
+               }
+
+               vp->op = op;
+               if (fr_pair_value_from_str(vp, s2, -1) < 0) {
+                       DEBUG("%s - Failed: '%s:%s' %s '%s'", funcname, list_name, s1,
+                             fr_int2str(fr_tokens, op, "="), s2);
                } else {
-                       DEBUG("rlm_python:%s: Failed: '%s' = '%s'", funcname, s1, s2);
+                       DEBUG("%s - '%s:%s' %s '%s'", funcname, list_name, s1,
+                             fr_int2str(fr_tokens, op, "="), s2);
                }
+
+               radius_pairmove(current, vps, vp, false);
        }
 }
 
@@ -364,46 +342,29 @@ static int mod_populate_vptuple(PyObject *pPair, VALUE_PAIR *vp)
        PyObject *pStr = NULL;
        char buf[1024];
 
-       /* Look at the vp_print_name? */
+       /* Look at the fr_pair_fprint_name? */
 
-       if (vp->da->flags.has_tag)
+       if (vp->da->flags.has_tag) {
                pStr = PyString_FromFormat("%s:%d", vp->da->name, vp->tag);
-       else
+       } else {
                pStr = PyString_FromString(vp->da->name);
+       }
 
-       if (!pStr)
-               goto failed;
+       if (!pStr) return -1;
 
        PyTuple_SET_ITEM(pPair, 0, pStr);
 
-       vp_prints_value(buf, sizeof(buf), vp, '"');
+       vp_prints_value(buf, sizeof(buf), vp, '\0');    /* Python doesn't need any escaping */
+
+       pStr = PyString_FromString(buf);
+       if (pStr == NULL) return -1;
 
-       if ((pStr = PyString_FromString(buf)) == NULL)
-               goto failed;
        PyTuple_SET_ITEM(pPair, 1, pStr);
 
        return 0;
-
-failed:
-       return -1;
 }
 
-#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)
+static rlm_rcode_t do_python_single(REQUEST *request, PyObject *pFunc, char const *funcname)
 {
        vp_cursor_t     cursor;
        VALUE_PAIR      *vp;
@@ -412,42 +373,6 @@ static rlm_rcode_t do_python(rlm_python_t *inst, REQUEST *request, PyObject *pFu
        int             tuplelen;
        int             ret;
 
-       PyGILState_STATE gstate;
-       PyThreadState   *prev_thread_state = NULL;      /* -Wuninitialized */
-       memset(&gstate, 0, sizeof(gstate));             /* -Wuninitialized */
-
-       /* 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;
 
@@ -463,9 +388,7 @@ static rlm_rcode_t do_python(rlm_python_t *inst, REQUEST *request, PyObject *pFu
        if (request != NULL) {
                for (vp = fr_cursor_init(&cursor, &request->packet->vps);
                     vp;
-                    vp = fr_cursor_next(&cursor)) {
-                       tuplelen++;
-               }
+                    vp = fr_cursor_next(&cursor)) tuplelen++;
        }
 
        if (tuplelen == 0) {
@@ -502,14 +425,16 @@ static rlm_rcode_t do_python(rlm_python_t *inst, REQUEST *request, PyObject *pFu
 
        /* Call Python function. */
        pRet = PyObject_CallFunctionObjArgs(pFunc, pArgs, NULL);
-
        if (!pRet) {
                ret = RLM_MODULE_FAIL;
                goto finish;
        }
 
-       if (!request)
+       if (!request) {
+               // check return code at module instantiation time
+               if (PyInt_CheckExact(pRet)) ret = PyInt_AsLong(pRet);
                goto finish;
+       }
 
        /*
         *      The function returns either:
@@ -528,25 +453,25 @@ static rlm_rcode_t do_python(rlm_python_t *inst, REQUEST *request, PyObject *pFu
                PyObject *pTupleInt;
 
                if (PyTuple_GET_SIZE(pRet) != 3) {
-                       ERROR("rlm_python:%s: tuple must be (return, replyTuple, configTuple)", funcname);
+                       ERROR("%s - Tuple must be (return, replyTuple, configTuple)", funcname);
                        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);
+                       ERROR("%s - First tuple element not an integer", funcname);
                        ret = RLM_MODULE_FAIL;
                        goto finish;
                }
                /* Now have the return value */
                ret = PyInt_AsLong(pTupleInt);
                /* Reply item tuple */
-               mod_vptuple(request->reply, &request->reply->vps,
-                           PyTuple_GET_ITEM(pRet, 1), funcname);
+               mod_vptuple(request->reply, request, &request->reply->vps,
+                           PyTuple_GET_ITEM(pRet, 1), funcname, "reply");
                /* Config item tuple */
-               mod_vptuple(request, &request->config,
-                           PyTuple_GET_ITEM(pRet, 2), funcname);
+               mod_vptuple(request, request, &request->config,
+                           PyTuple_GET_ITEM(pRet, 2), funcname, "config");
 
        } else if (PyInt_CheckExact(pRet)) {
                /* Just an integer */
@@ -557,96 +482,434 @@ static rlm_rcode_t do_python(rlm_python_t *inst, REQUEST *request, PyObject *pFu
                ret = RLM_MODULE_OK;
        } else {
                /* Not tuple or None */
-               ERROR("rlm_python:%s: function did not return a tuple or None", funcname);
+               ERROR("%s - Function did not return a tuple or None", funcname);
                ret = RLM_MODULE_FAIL;
                goto finish;
        }
 
+
 finish:
        Py_XDECREF(pArgs);
        Py_XDECREF(pRet);
 
-#ifdef HAVE_PTHREAD_H
-       if (worker) {
-               PyThreadState_Swap(prev_thread_state);
-       }
-       PyGILState_Release(gstate);
-#endif
-
        return ret;
 }
 
-/*
- *     Import a user module and load a function from it
+static void python_interpreter_free(PyThreadState *interp)
+{
+       PyEval_AcquireLock();
+       PyThreadState_Swap(interp);
+       Py_EndInterpreter(interp);
+       PyEval_ReleaseLock();
+}
+
+/** Destroy a thread state
+ *
+ * @param thread to destroy.
+ * @return 0
  */
+static int _python_thread_free(python_thread_state_t *thread)
+{
+       PyEval_RestoreThread(thread->state);    /* Swap in our local thread state */
+       PyThreadState_Clear(thread->state);
+       PyEval_SaveThread();
 
-static int mod_load_function(struct py_function_def *def)
+       PyThreadState_Delete(thread->state);    /* Don't need to hold lock for this */
+
+       return 0;
+}
+
+/** Callback for rbtree delete walker
+ *
+ */
+static void _python_thread_entry_free(void *arg)
 {
-       char const *funcname = "mod_load_function";
-       PyGILState_STATE gstate;
+       talloc_free(arg);
+}
+
+/** Cleanup any thread local storage on pthread_exit()
+ *
+ * @param arg The thread currently exiting.
+ */
+static void _python_thread_tree_free(void *arg)
+{
+       rad_assert(arg == local_thread_state);
+
+       rbtree_t *tree = talloc_get_type_abort(arg, rbtree_t);
+       rbtree_free(tree);      /* Needs to be this not talloc_free to execute delete walker */
+
+       local_thread_state = NULL;      /* Prevent double free in unittest env */
+}
 
-       gstate = PyGILState_Ensure();
+/** Compare instance pointers
+ *
+ */
+static int _python_inst_cmp(const void *a, const void *b)
+{
+       python_thread_state_t const *a_p = a, *b_p = b;
 
-       if (def->module_name != NULL && def->function_name != NULL) {
-               if ((def->module = PyImport_ImportModule(def->module_name)) == NULL) {
-                       ERROR("rlm_python:%s: module '%s' is not found", funcname, def->module_name);
-                       goto failed;
+       if (a_p->inst < b_p->inst) return -1;
+       if (a_p->inst > b_p->inst) return +1;
+       return 0;
+}
+
+/** Thread safe call to a python function
+ *
+ * Will swap in thread state specific to module/thread.
+ */
+static rlm_rcode_t do_python(rlm_python_t *inst, REQUEST *request, PyObject *pFunc, char const *funcname)
+{
+       int                     ret;
+       rbtree_t                *thread_tree;
+       python_thread_state_t   *this_thread;
+       python_thread_state_t   find;
+
+       /*
+        *      It's a NOOP if the function wasn't defined
+        */
+       if (!pFunc) return RLM_MODULE_NOOP;
+
+       /*
+        *      Check to see if we've got a thread state tree
+        *      If not, create one.
+        */
+       thread_tree = fr_thread_local_init(local_thread_state, _python_thread_tree_free);
+       if (!thread_tree) {
+               thread_tree = rbtree_create(NULL, _python_inst_cmp, _python_thread_entry_free, 0);
+               if (!thread_tree) {
+                       RERROR("Failed allocating thread state tree");
+                       return RLM_MODULE_FAIL;
                }
 
-               if ((def->function = PyObject_GetAttrString(def->module, def->function_name)) == NULL) {
-                       ERROR("rlm_python:%s: function '%s.%s' is not found", funcname, def->module_name, def->function_name);
-                       goto failed;
+               ret = fr_thread_local_set(local_thread_state, thread_tree);
+               if (ret != 0) {
+                       talloc_free(thread_tree);
+                       return RLM_MODULE_FAIL;
                }
+       }
+
+       find.inst = inst;
+       /*
+        *      Find the thread state associated with this instance
+        *      and this thread, or create a new thread state.
+        */
+       this_thread = rbtree_finddata(thread_tree, &find);
+       if (!this_thread) {
+               PyThreadState *state;
 
-               if (!PyCallable_Check(def->function)) {
-                       ERROR("rlm_python:%s: function '%s.%s' is not callable", funcname, def->module_name, def->function_name);
-                       goto failed;
+               state = PyThreadState_New(inst->sub_interpreter->interp);
+
+               RDEBUG3("Initialised new thread state %p", state);
+               if (!state) {
+                       REDEBUG("Failed initialising local PyThreadState on first run");
+                       return RLM_MODULE_FAIL;
+               }
+
+               this_thread = talloc(NULL, python_thread_state_t);
+               this_thread->inst = inst;
+               this_thread->state = state;
+               talloc_set_destructor(this_thread, _python_thread_free);
+
+               if (!rbtree_insert(thread_tree, this_thread)) {
+                       RERROR("Failed inserting thread state into TLS tree");
+                       talloc_free(this_thread);
+
+                       return RLM_MODULE_FAIL;
                }
        }
-       PyGILState_Release(gstate);
-       return 0;
+       RDEBUG3("Using thread state %p", this_thread->state);
 
-failed:
-       mod_error();
-       ERROR("rlm_python:%s: failed to import python function '%s.%s'", funcname, def->module_name, def->function_name);
-       Py_XDECREF(def->function);
-       def->function = NULL;
-       Py_XDECREF(def->module);
-       def->module = NULL;
-       PyGILState_Release(gstate);
-       return -1;
+       PyEval_RestoreThread(this_thread->state);       /* Swap in our local thread state */
+       ret = do_python_single(request, pFunc, funcname);
+       PyEval_SaveThread();
+
+       return ret;
 }
 
+#define MOD_FUNC(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);\
+}
 
-static void mod_objclear(PyObject **ob)
+MOD_FUNC(authenticate)
+MOD_FUNC(authorize)
+MOD_FUNC(preacct)
+MOD_FUNC(accounting)
+MOD_FUNC(checksimul)
+MOD_FUNC(pre_proxy)
+MOD_FUNC(post_proxy)
+MOD_FUNC(post_auth)
+#ifdef WITH_COA
+MOD_FUNC(recv_coa)
+MOD_FUNC(send_coa)
+#endif
+static void python_obj_destroy(PyObject **ob)
 {
        if (*ob != NULL) {
-               Pyx_BLOCK_THREADS
                Py_DECREF(*ob);
-               Pyx_UNBLOCK_THREADS
                *ob = NULL;
        }
 }
 
-static void mod_funcdef_clear(struct py_function_def *def)
+static void python_function_destroy(python_func_def_t *def)
 {
-       mod_objclear(&def->function);
-       mod_objclear(&def->module);
+       python_obj_destroy(&def->function);
+       python_obj_destroy(&def->module);
 }
 
-static void mod_instance_clear(rlm_python_t *inst)
+/** Import a user module and load a function from it
+ *
+ */
+static int python_function_load(python_func_def_t *def)
 {
-#define A(x) mod_funcdef_clear(&inst->x)
+       char const *funcname = "python_function_load";
 
-       A(instantiate);
-       A(authorize);
-       A(authenticate);
-       A(preacct);
-       A(accounting);
-       A(checksimul);
-       A(detach);
+       if (def->module_name == NULL || def->function_name == NULL) return 0;
 
-#undef A
+       def->module = PyImport_ImportModule(def->module_name);
+       if (!def->module) {
+               ERROR("%s - Module '%s' not found", funcname, def->module_name);
+
+       error:
+               python_error_log();
+               ERROR("%s - Failed to import python function '%s.%s'",
+                     funcname, def->module_name, def->function_name);
+               Py_XDECREF(def->function);
+               def->function = NULL;
+               Py_XDECREF(def->module);
+               def->module = NULL;
+
+               return -1;
+       }
+
+       def->function = PyObject_GetAttrString(def->module, def->function_name);
+       if (!def->function) {
+               ERROR("%s - Function '%s.%s' is not found", funcname, def->module_name, def->function_name);
+               goto error;
+       }
+
+       if (!PyCallable_Check(def->function)) {
+               ERROR("%s - Function '%s.%s' is not callable", funcname, def->module_name, def->function_name);
+               goto error;
+       }
+
+       return 0;
+}
+
+/*
+ *     Parse a configuration section, and populate a dict.
+ *     This function is recursively called (allows to have nested dicts.)
+ */
+static void python_parse_config(CONF_SECTION *cs, int lvl, PyObject *dict)
+{
+       int             indent_section = (lvl + 1) * 4;
+       int             indent_item = (lvl + 2) * 4;
+       CONF_ITEM       *ci = NULL;
+
+       if (!cs || !dict) return;
+
+       DEBUG("%*s%s {", indent_section, " ", cf_section_name1(cs));
+
+       while ((ci = cf_item_find_next(cs, ci))) {
+               /*
+                *  This is a section.
+                *  Create a new dict, store it in current dict,
+                *  Then recursively call python_parse_config with this section and the new dict.
+                */
+               if (cf_item_is_section(ci)) {
+                       CONF_SECTION *sub_cs = cf_item_to_section(ci);
+                       char const *key = cf_section_name1(sub_cs); /* dict key */
+                       PyObject *sub_dict, *pKey;
+
+                       if (!key) continue;
+
+                       pKey = PyString_FromString(key);
+                       if (!pKey) continue;
+
+                       if (PyDict_Contains(dict, pKey)) {
+                               WARN("rlm_python: Ignoring duplicate config section '%s'", key);
+                               continue;
+                       }
+
+                       if (!(sub_dict = PyDict_New())) {
+                               WARN("rlm_python: Unable to create subdict for config section '%s'", key);
+                       }
+
+                       (void)PyDict_SetItem(dict, pKey, sub_dict);
+
+                       python_parse_config(sub_cs, lvl + 1, sub_dict);
+               } else if (cf_item_is_pair(ci)) {
+                       CONF_PAIR *cp = cf_item_to_pair(ci);
+                       char const  *key = cf_pair_attr(cp); /* dict key */
+                       char const  *value = cf_pair_value(cp); /* dict value */
+                       PyObject *pKey, *pValue;
+
+                       if (!key || !value) continue;
+
+                       pKey = PyString_FromString(key);
+                       pValue = PyString_FromString(value);
+                       if (!pKey || !pValue) continue;
+
+                       /*
+                        *  This is an item.
+                        *  Store item attr / value in current dict.
+                        */
+                       if (PyDict_Contains(dict, pKey)) {
+                               WARN("rlm_python: Ignoring duplicate config item '%s'", key);
+                               continue;
+                       }
+
+                       (void)PyDict_SetItem(dict, pKey, pValue);
+
+                       DEBUG("%*s%s = %s", indent_item, " ", key, value);
+               }
+       }
+
+       DEBUG("%*s}", indent_section, " ");
+}
+
+/** Initialises a separate python interpreter for this module instance
+ *
+ */
+static int python_interpreter_init(rlm_python_t *inst, CONF_SECTION *conf)
+{
+       int i;
+
+       /*
+        *      Explicitly load libpython, so symbols will be available to lib-dynload modules
+        */
+       if (python_instances == 0) {
+               INFO("Python version: %s", Py_GetVersion());
+
+               python_dlhandle = dlopen("libpython" STRINGIFY(PY_MAJOR_VERSION) "." STRINGIFY(PY_MINOR_VERSION) ".so",
+                                        RTLD_NOW | RTLD_GLOBAL);
+               if (!python_dlhandle) WARN("Failed loading libpython symbols into global symbol table: %s", dlerror());
+
+#if PY_VERSION_HEX > 0x03050000
+               {
+                       wchar_t *name;
+
+                       wide_name = Py_DecodeLocale(main_config.name, strlen(main_config.name));
+                       Py_SetProgramName(name);                /* The value of argv[0] as a wide char string */
+                       PyMem_RawFree(name);
+               }
+#else
+               {
+                       char *name;
+
+                       name = talloc_strdup(NULL, main_config.name);
+                       Py_SetProgramName(name);                /* The value of argv[0] as a wide char string */
+                       talloc_free(name);
+               }
+#endif
+
+               Py_InitializeEx(0);                     /* Don't override signal handlers - noop on subs calls */
+               PyEval_InitThreads();                   /* This also grabs a lock (which we then need to release) */
+               main_interpreter = PyThreadState_Get(); /* Store reference to the main interpreter */
+       }
+       rad_assert(PyEval_ThreadsInitialized());
+
+       /*
+        *      Increment the reference counter
+        */
+       python_instances++;
+
+       /*
+        *      This sets up a separate environment for each python module instance
+        *      These will be destroyed on Py_Finalize().
+        */
+       if (!inst->cext_compat) {
+               inst->sub_interpreter = Py_NewInterpreter();
+       } else {
+               inst->sub_interpreter = main_interpreter;
+       }
+
+       PyThreadState_Swap(inst->sub_interpreter);
+
+       /*
+        *      Due to limitations in Python, sub-interpreters don't work well
+        *      with Python C extensions if they use GIL lock functions.
+        */
+       if (!inst->cext_compat || !main_module) {
+               CONF_SECTION *cs;
+
+               /*
+                *      Set the python search path
+                */
+               if (inst->python_path) {
+#if PY_VERSION_HEX > 0x03050000
+                       {
+                               wchar_t *name;
+
+                               path = Py_DecodeLocale(inst->python_path, strlen(inst->python_path));
+                               PySys_SetPath(path);
+                               PyMem_RawFree(path);
+                       }
+#else
+                       {
+                               char *path;
+
+                               path = talloc_strdup(NULL, inst->python_path);
+                               PySys_SetPath(path);
+                               talloc_free(path);
+                       }
+#endif
+               }
+
+               /*
+                *      Initialise a new module, with our default methods
+                */
+               inst->module = Py_InitModule3("radiusd", module_methods, "FreeRADIUS python module");
+               if (!inst->module) {
+               error:
+                       python_error_log();
+                       PyEval_SaveThread();
+                       return -1;
+               }
+
+               /*
+                *      Py_InitModule3 returns a borrowed ref, the actual
+                *      module is owned by sys.modules, so we also need
+                *      to own the module to prevent it being freed early.
+                */
+               Py_IncRef(inst->module);
+
+               if (inst->cext_compat) main_module = inst->module;
+
+               for (i = 0; radiusd_constants[i].name; i++) {
+                       if ((PyModule_AddIntConstant(inst->module, radiusd_constants[i].name,
+                                                    radiusd_constants[i].value)) < 0)
+                               goto error;
+               }
+
+               /*
+                *      Convert a FreeRADIUS config structure into a python
+                *      dictionary.
+                */
+               inst->pythonconf_dict = PyDict_New();
+               if (!inst->pythonconf_dict) {
+                       ERROR("Unable to create python dict for config");
+                       python_error_log();
+                       return -1;
+               }
+
+               /*
+                *      Add module configuration as a dict
+                */
+               if (PyModule_AddObject(inst->module, "config", inst->pythonconf_dict) < 0) goto error;
+
+               cs = cf_section_sub_find(conf, "config");
+               if (cs) python_parse_config(cs, 0, inst->pythonconf_dict);
+       } else {
+               inst->module = main_module;
+               Py_IncRef(inst->module);
+               inst->pythonconf_dict = PyObject_GetAttrString(inst->module, "config");
+               Py_IncRef(inst->pythonconf_dict);
+       }
+
+       PyEval_SaveThread();
+
+       return 0;
 }
 
 /*
@@ -660,44 +923,56 @@ static void mod_instance_clear(rlm_python_t *inst)
  *     in *instance otherwise put a null pointer there.
  *
  */
-static int mod_instantiate(UNUSED CONF_SECTION *conf, void *instance)
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
 {
-       rlm_python_t *inst = instance;
+       rlm_python_t    *inst = instance;
+       int             code = 0;
 
-       if (mod_init(inst) != 0) {
-               return -1;
-       }
+       inst->name = cf_section_name2(conf);
+       if (!inst->name) inst->name = cf_section_name1(conf);
+
+       /*
+        *      Load the python code required for this module instance
+        */
+       if (python_interpreter_init(inst, conf) < 0) return -1;
+
+       /*
+        *      Switch to our module specific main thread
+        */
+       PyEval_RestoreThread(inst->sub_interpreter);
 
-#define A(x) if (mod_load_function(&inst->x) < 0) goto failed
-
-       A(instantiate);
-       A(authenticate);
-       A(authorize);
-       A(preacct);
-       A(accounting);
-       A(checksimul);
-       A(pre_proxy);
-       A(post_proxy);
-       A(post_auth);
+       /*
+        *      Process the various sections
+        */
+#define PYTHON_FUNC_LOAD(_x) if (python_function_load(&inst->_x) < 0) goto error
+       PYTHON_FUNC_LOAD(instantiate);
+       PYTHON_FUNC_LOAD(authenticate);
+       PYTHON_FUNC_LOAD(authorize);
+       PYTHON_FUNC_LOAD(preacct);
+       PYTHON_FUNC_LOAD(accounting);
+       PYTHON_FUNC_LOAD(checksimul);
+       PYTHON_FUNC_LOAD(pre_proxy);
+       PYTHON_FUNC_LOAD(post_proxy);
+       PYTHON_FUNC_LOAD(post_auth);
 #ifdef WITH_COA
-       A(recv_coa);
-       A(send_coa);
+       PYTHON_FUNC_LOAD(recv_coa);
+       PYTHON_FUNC_LOAD(send_coa);
 #endif
-       A(detach);
-
-#undef A
+       PYTHON_FUNC_LOAD(detach);
 
        /*
-        *      Call the instantiate function.  No request.  Use the
-        *      return value.
+        *      Call the instantiate function.
         */
-       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;
+       code = do_python_single(NULL, inst->instantiate.function, "instantiate");
+       if (code < 0) {
+       error:
+               python_error_log();     /* Needs valid thread with GIL */
+               PyEval_SaveThread();
+               return -1;
+       }
+       PyEval_SaveThread();
+
+       return 0;
 }
 
 static int mod_detach(void *instance)
@@ -706,34 +981,48 @@ static int mod_detach(void *instance)
        int          ret;
 
        /*
-        *      Master should still have no thread state
+        *      Call module destructor
         */
-       ret = do_python(inst, NULL, inst->detach.function, "detach", false);
+       PyEval_RestoreThread(inst->sub_interpreter);
 
-       mod_instance_clear(inst);
-       dlclose(inst->libpython);
+       ret = do_python_single(NULL, inst->detach.function, "detach");
 
-       return ret;
-}
+#define PYTHON_FUNC_DESTROY(_x) python_function_destroy(&inst->_x)
+       PYTHON_FUNC_DESTROY(instantiate);
+       PYTHON_FUNC_DESTROY(authorize);
+       PYTHON_FUNC_DESTROY(authenticate);
+       PYTHON_FUNC_DESTROY(preacct);
+       PYTHON_FUNC_DESTROY(accounting);
+       PYTHON_FUNC_DESTROY(checksimul);
+       PYTHON_FUNC_DESTROY(detach);
 
-#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);\
-       }
+       Py_DecRef(inst->pythonconf_dict);
+       Py_DecRef(inst->module);
 
-A(authenticate)
-A(authorize)
-A(preacct)
-A(accounting)
-A(checksimul)
-A(pre_proxy)
-A(post_proxy)
-A(post_auth)
-#ifdef WITH_COA
-A(recv_coa)
-A(send_coa)
-#endif
+       PyEval_SaveThread();
 
-#undef A
+       /*
+        *      Force cleaning up of threads if this is *NOT* a worker
+        *      thread, which happens if this is being called from
+        *      unittest framework, and probably with the server running
+        *      in debug mode.
+        */
+       rbtree_free(local_thread_state);
+       local_thread_state = NULL;
+
+       /*
+        *      Only destroy if it's a subinterpreter
+        */
+       if (!inst->cext_compat) python_interpreter_free(inst->sub_interpreter);
+
+       if ((--python_instances) == 0) {
+               PyThreadState_Swap(main_interpreter); /* Swap to the main thread */
+               Py_Finalize();
+               dlclose(python_dlhandle);
+       }
+
+       return ret;
+}
 
 /*
  *     The module name should be the only globally exported symbol.
index b2cc178..cc01c8b 100644 (file)
@@ -171,8 +171,11 @@ static int check_for_realm(void *instance, REQUEST *request, REALM **returnrealm
        /*
         *      Try querying for the dynamic realm.
         */
-       if (!realm && inst->trust_router)
+       if (!realm && inst->trust_router) {
                realm = tr_query_realm(request, realmname, inst->default_community, inst->rp_realm, inst->trust_router, inst->tr_port);
+       } else {
+               RDEBUG2("No trust router configured, skipping dynamic realm lookup");
+       }
 #endif
 
        if (!realm) {
@@ -220,8 +223,14 @@ static int check_for_realm(void *instance, REQUEST *request, REALM **returnrealm
         *      entered.
         */
        if (realm->name[0] != '~') realmname = realm->name;
-       pair_make_request("Realm", realmname, T_OP_EQ);
-       RDEBUG2("Adding Realm = \"%s\"", realmname);
+
+       /*
+        *      A NULL realmname is allowed.
+        */
+       if (realmname) {
+               pair_make_request("Realm", realmname, T_OP_EQ);
+               RDEBUG2("Adding Realm = \"%s\"", realmname);
+       }
 
        talloc_free(namebuf);
        username = NULL;
@@ -299,6 +308,8 @@ static int check_for_realm(void *instance, REQUEST *request, REALM **returnrealm
                 *      send it there again.
                 */
                for (i = 0; i < realm->acct_pool->num_home_servers; i++) {
+                       if (realm->acct_pool->servers[i]->ipaddr.af == AF_UNSPEC) continue;
+
                        if (fr_ipaddr_cmp(&realm->acct_pool->servers[i]->ipaddr, &my_ipaddr) == 0) {
                                RDEBUG2("Suppressing proxy due to FreeRADIUS-Proxied-To");
                                return RLM_MODULE_OK;
@@ -322,6 +333,8 @@ static int check_for_realm(void *instance, REQUEST *request, REALM **returnrealm
                 *      send it there again.
                 */
                for (i = 0; i < realm->acct_pool->num_home_servers; i++) {
+                       if (realm->acct_pool->servers[i]->ipaddr.af == AF_UNSPEC) continue;
+
                        if ((fr_ipaddr_cmp(&realm->acct_pool->servers[i]->ipaddr,
                                             &request->packet->src_ipaddr) == 0) &&
                            (realm->acct_pool->servers[i]->port == request->packet->src_port)) {
@@ -378,6 +391,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance)
                if (!tr_init()) return -1;
        } else {
                rad_const_free(inst->trust_router);
+               inst->trust_router = NULL;
        }
 #endif
 
index eb68375..918ca09 100644 (file)
@@ -2042,7 +2042,16 @@ int rest_request_config(rlm_rest_t *instance, rlm_rest_section_t *section,
                break;
 
        case HTTP_METHOD_PUT:
-               SET_OPTION(CURLOPT_PUT, 1L);
+               /*
+                *      Do not set CURLOPT_PUT, this will cause libcurl
+                *      to ignore CURLOPT_POSTFIELDs and attempt to read
+                *      whatever was set with CURLOPT_READDATA, which by
+                *      default is stdin.
+                *
+                *      This is many cases will cause the server to block,
+                *      indefinitely.
+                */
+               SET_OPTION(CURLOPT_CUSTOMREQUEST, "PUT");
                break;
 
        case HTTP_METHOD_PATCH:
index cc5bb5c..26ca0bb 100644 (file)
@@ -279,14 +279,20 @@ static ssize_t rest_xlat(void *instance, REQUEST *request,
        ret = rest_request_config(instance, &section, request, handle, section.method, section.body,
                                  uri, NULL, NULL);
        talloc_free(uri);
-       if (ret < 0) return -1;
+       if (ret < 0) {
+               outlen = -1;
+               goto finish;
+       }
 
        /*
         *  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;
+       if (ret < 0) {
+               outlen = -1;
+               goto finish;
+       }
 
        hcode = rest_get_handle_code(handle);
        switch (hcode) {
index 3abc2c7..ad2f15f 100644 (file)
@@ -42,7 +42,9 @@ RCSID("$Id$")
  */
 #undef HAVE_CRYPT
 
+#ifdef __clang__
 DIAG_OFF(disabled-macro-expansion)
+#endif
 #include <ruby.h>
 
 /*
diff --git a/src/modules/rlm_sql/README b/src/modules/rlm_sql/README
deleted file mode 100644 (file)
index 325302f..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-FreeRADIUS SQL Module
-
-The core rlm_sql code handles database indepenent stuff and links the specific database drivers depending on your config. Sample sql configurations can be found in the raddb/sql.conf file.
-
-
-Mike Machado
-mike@innercite.com
-InnerCite Inc.
-Engineering Director / CTO
-
-Returning 'SQL_DOWN' allows sql.c to reconnect and try again, in most cases
-
-sql_select_query: returns -1 on failure, SQL_DOWN on 'socket not connected'
-sql_query: returns -1 on failure, SQL_DOWN on 'socket not connected'
-sql_store_result: returns -1 on failure, SQL_DOWN on 'socket not connected'
-sql_num_fields: cannot return an error, complains if zero fields
-sql_finish_select_query: returns 0 always
-sql_finish_query: does nothing, returns 0
-sql_free_result: returns 0 always, mysql_free_result has no return value
-sql_release_socket: returns 1 always
-sql_fetch_row: returns 0 if ok, SQL_DOWN on 'socket not connected', row is
-               in sqlsocket->row now
-
-TODO:
-
-db2/iodbc/unixodbc:
-     for the above functions, where it can return SQL_DOWN, determine if an
-     error with the database exists, if it is down, and return SQL_DOWN
-
index d37482f..91d161f 100644 (file)
@@ -389,9 +389,15 @@ static int sql_num_fields(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *con
        rlm_sql_mysql_conn_t *conn = handle->conn;
 
 #if MYSQL_VERSION_ID >= 32224
+       /*
+        *      Count takes a connection handle
+        */
        if (!(num = mysql_field_count(conn->sock))) {
 #else
-       if (!(num = mysql_num_fields(conn->sock))) {
+       /*
+        *      Fields takes a result struct
+        */
+       if (!(num = mysql_num_fields(conn->result))) {
 #endif
                return -1;
        }
index d79fb72..4dfa0ef 100644 (file)
@@ -169,7 +169,7 @@ static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *c
         */
        if (OCIHandleAlloc((dvoid *)conn->env, (dvoid **)&conn->query, OCI_HTYPE_STMT, 0, NULL)) {
                ERROR("rlm_sql_oracle: Couldn't init Oracle query handles: %s",
-                     sql_prints_error(errbuff, sizeof(errbuff), handle, config) ? errbuff : "unknown");
+                     (sql_prints_error(errbuff, sizeof(errbuff), handle, config) == 0) ? errbuff : "unknown");
 
                return RLM_SQL_ERROR;
        }
@@ -182,7 +182,7 @@ static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *c
                     (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_prints_error(errbuff, sizeof(errbuff), handle, config) ? errbuff : "unknown");
+                     (sql_prints_error(errbuff, sizeof(errbuff), handle, config) == 0) ? errbuff : "unknown");
 
                return RLM_SQL_ERROR;
        }
@@ -444,6 +444,12 @@ static sql_rcode_t sql_fetch_row(rlm_sql_handle_t *handle, rlm_sql_config_t *con
                return RLM_SQL_OK;
        }
 
+       if (status == OCI_NO_DATA) {
+               handle->row = 0;
+
+               return RLM_SQL_OK;
+       }
+
        if (status == OCI_ERROR) {
                ERROR("rlm_sql_oracle: fetch failed in sql_fetch_row");
                return sql_check_error(handle, config);
index 1c2034e..eb348df 100644 (file)
@@ -113,7 +113,7 @@ static int mod_instantiate(CONF_SECTION *conf, rlm_sql_config_t *config)
                if (!name) name = cf_section_name1(cs);
 
                snprintf(application_name, sizeof(application_name),
-                        "FreeRADIUS " RADIUSD_VERSION_STRING " - %s (%s)", progname, name);
+                        "FreeRADIUS " RADIUSD_VERSION_STRING " - %s (%s)", main_config.name, name);
        }
 
        /*
index f0168b1..4b89d86 100644 (file)
@@ -45,7 +45,7 @@ RCSID("$Id$")
 #endif
 
 #ifndef HAVE_SQLITE3_INT64
-typedef sqlite3_int64 sqlite_int64
+typedef sqlite_int64 sqlite3_int64;
 #endif
 
 typedef struct rlm_sql_sqlite_conn {
@@ -665,6 +665,8 @@ static sql_rcode_t sql_fetch_row(rlm_sql_handle_t *handle, rlm_sql_config_t *con
 
        char **row;
 
+       TALLOC_FREE(handle->row);
+
        /*
         *      Executes the SQLite query and interates over the results
         */
@@ -691,11 +693,6 @@ static sql_rcode_t sql_fetch_row(rlm_sql_handle_t *handle, rlm_sql_config_t *con
                if (conn->col_count == 0) return RLM_SQL_ERROR;
        }
 
-       /*
-        *      Free the previous result (also gets called on finish_query)
-        */
-       talloc_free(handle->row);
-
        MEM(row = handle->row = talloc_zero_array(handle->conn, char *, conn->col_count + 1));
 
        for (i = 0; i < conn->col_count; i++) {
index 5b53953..fafcd63 100644 (file)
@@ -225,10 +225,7 @@ static ssize_t sql_xlat(void *instance, REQUEST *request, char const *query, cha
        if (rcode != RLM_SQL_OK) goto query_error;
 
        rcode = rlm_sql_fetch_row(inst, request, &handle);
-       if (rcode) {
-               (inst->module->sql_finish_select_query)(handle, inst->config);
-               goto query_error;
-       }
+       if (rcode) goto query_error;
 
        row = handle->row;
        if (!row) {
@@ -501,8 +498,13 @@ int sql_set_user(rlm_sql_t *inst, REQUEST *request, char const *username)
 
        fr_pair_value_strsteal(vp, expanded);
        RDEBUG2("SQL-User-Name set to '%s'", vp->vp_strvalue);
-       vp->op = T_OP_SET;
-       radius_pairmove(request, &request->packet->vps, vp, false);     /* needs to be pair move else op is not respected */
+       vp->op = T_OP_SET;      
+
+       /*
+        *      Delete any existing SQL-User-Name, and replace it with ours.
+        */
+       fr_pair_delete_by_num(&request->packet->vps, vp->da->attr, vp->da->vendor, TAG_ANY);
+       fr_pair_add(&request->packet->vps, vp);
 
        return 0;
 }
@@ -1009,7 +1011,7 @@ do { \
                }
        }
 
-       inst->ef = exfile_init(inst, 64, 30, true);
+       inst->ef = exfile_init(inst, 256, 30, true);
        if (!inst->ef) {
                cf_log_err_cs(conf, "Failed creating log file context");
                return -1;
@@ -1503,10 +1505,11 @@ static rlm_rcode_t mod_checksimul(void *instance, REQUEST * request)
 
        /* If simul_count_query is not defined, we don't do any checking */
        if (!inst->config->simul_count_query) {
+               RWDEBUG("Simultaneous-Use checking requires 'simul_count_query' to be configured");
                return RLM_MODULE_NOOP;
        }
 
-       if ((!request->username) || (request->username->vp_length == '\0')) {
+       if ((!request->username) || (request->username->vp_length == 0)) {
                REDEBUG("Zero Length username not permitted");
 
                return RLM_MODULE_INVALID;
@@ -1531,7 +1534,7 @@ static rlm_rcode_t mod_checksimul(void *instance, REQUEST * request)
 
        if (rlm_sql_select_query(inst, request, &handle, expanded) != RLM_SQL_OK) {
                rcode = RLM_MODULE_FAIL;
-               goto finish;
+               goto release;   /* handle may no longer be valid */
        }
 
        ret = rlm_sql_fetch_row(inst, request, &handle);
index 0451002..643d68a 100644 (file)
@@ -53,17 +53,6 @@ const FR_NAME_NUMBER sql_rcode_table[] = {
 };
 
 
-static int _mod_conn_free(rlm_sql_handle_t *conn)
-{
-       rlm_sql_t *inst = conn->inst;
-
-       rad_assert(inst);
-
-       exec_trigger(NULL, inst->cs, "modules.sql.close", false);
-
-       return 0;
-}
-
 void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
 {
        int rcode;
@@ -89,19 +78,9 @@ void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
         */
        handle->inst = inst;
 
-       /*
-        *      When something frees this handle the destructor set by
-        *      the driver will be called first, closing any open sockets.
-        *      Then we call our destructor to trigger an modules.sql.close
-        *      event, then all the memory is freed.
-        */
-       talloc_set_destructor(handle, _mod_conn_free);
-
        rcode = (inst->module->sql_socket_init)(handle, inst->config);
        if (rcode != 0) {
        fail:
-               exec_trigger(NULL, inst->cs, "modules.sql.fail", true);
-
                /*
                 *      Destroy any half opened connections.
                 */
@@ -114,7 +93,6 @@ void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
                (inst->module->sql_finish_select_query)(handle, inst->config);
        }
 
-       exec_trigger(NULL, inst->cs, "modules.sql.open", false);
        return handle;
 }
 
@@ -131,13 +109,13 @@ int sql_fr_pair_list_afrom_str(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **h
        char const *ptr, *value;
        char buf[MAX_STRING_LEN];
        char do_xlat = 0;
-       FR_TOKEN token, operator = T_EOL;
+       FR_TOKEN token, op = T_EOL;
 
        /*
         *      Verify the 'Attribute' field
         */
        if (!row[2] || row[2][0] == '\0') {
-               REDEBUG("The 'Attribute' field is empty or NULL, skipping the entire row");
+               REDEBUG("Attribute field is empty or NULL, skipping the entire row");
                return -1;
        }
 
@@ -146,10 +124,9 @@ int sql_fr_pair_list_afrom_str(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **h
         */
        if (row[4] != NULL && row[4][0] != '\0') {
                ptr = row[4];
-               operator = gettoken(&ptr, buf, sizeof(buf), false);
-               if ((operator < T_OP_ADD) ||
-                   (operator > T_OP_CMP_EQ)) {
-                       REDEBUG("Invalid operator \"%s\" for attribute %s", row[4], row[2]);
+               op = gettoken(&ptr, buf, sizeof(buf), false);
+               if (!fr_assignment_op[op] && !fr_equality_op[op]) {
+                       REDEBUG("Invalid op \"%s\" for attribute %s", row[4], row[2]);
                        return -1;
                }
 
@@ -157,15 +134,21 @@ int sql_fr_pair_list_afrom_str(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **h
                /*
                 *  Complain about empty or invalid 'op' field
                 */
-               operator = T_OP_CMP_EQ;
-               REDEBUG("The 'op' field for attribute '%s = %s' is NULL, or non-existent.", row[2], row[3]);
+               op = T_OP_CMP_EQ;
+               REDEBUG("The op field for attribute '%s = %s' is NULL, or non-existent.", row[2], row[3]);
                REDEBUG("You MUST FIX THIS if you want the configuration to behave as you expect");
        }
 
        /*
         *      The 'Value' field may be empty or NULL
         */
+       if (!row[3]) {
+               REDEBUG("Value field is empty or NULL, skipping the entire row");
+               return -1;
+       }
+
        value = row[3];
+
        /*
         *      If we have a new-style quoted string, where the
         *      *entire* string is quoted, do xlat's.
@@ -188,9 +171,9 @@ int sql_fr_pair_list_afrom_str(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **h
                 *      Mark the pair to be allocated later.
                 */
                case T_BACK_QUOTED_STRING:
-                       value = NULL;
                        do_xlat = 1;
-                       break;
+
+                       /* FALL-THROUGH */
 
                /*
                 *      Keep the original string.
@@ -204,7 +187,7 @@ int sql_fr_pair_list_afrom_str(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **h
        /*
         *      Create the pair
         */
-       vp = fr_pair_make(ctx, NULL, row[2], NULL, operator);
+       vp = fr_pair_make(ctx, NULL, row[2], NULL, op);
        if (!vp) {
                REDEBUG("Failed to create the pair: %s", fr_strerror());
                return -1;
@@ -212,7 +195,7 @@ int sql_fr_pair_list_afrom_str(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **h
 
        if (do_xlat) {
                if (fr_pair_mark_xlat(vp, value) < 0) {
-                       REDEBUG("Error marking pair for xlat");
+                       REDEBUG("Error marking pair for xlat: %s", fr_strerror());
 
                        talloc_free(vp);
                        return -1;
@@ -535,13 +518,10 @@ void rlm_sql_query_log(rlm_sql_t *inst, REQUEST *request,
        size_t len;
        bool failed = false;    /* Write the log message outside of the critical region */
 
-       if (section) {
-               filename = section->logfile;
-       } else {
-               filename = inst->config->logfile;
-       }
+       filename = inst->config->logfile;
+       if (section && section->logfile) filename = section->logfile;
 
-       if (!filename) {
+       if (!filename || !*filename) {
                return;
        }
 
index 1685e37..7d23dd2 100644 (file)
@@ -4,3 +4,4 @@ rlm_sql_postgresql
 rlm_sql_oracle
 rlm_sql_unixodbc
 rlm_sql_sqlite
+rlm_sql_freetds
index 063bbed..7fdcb3a 100644 (file)
@@ -217,7 +217,7 @@ static int find_prev_reset(rlm_sqlcounter_t *inst, time_t timeval)
                 *  Round down to the prev nearest week.
                 */
                tm->tm_hour = 0;
-               tm->tm_mday -= (7 - tm->tm_wday) +(7*(num-1));
+               tm->tm_mday -= tm->tm_wday +(7*(num-1));
                inst->last_reset = mktime(tm);
        } else if (strcmp(inst->reset, "monthly") == 0 || last == 'm') {
                tm->tm_hour = 0;
index c99d039..40245bc 100644 (file)
@@ -289,7 +289,8 @@ static int sqlippool_expand(char * out, int outlen, char const * fmt,
  * @param param_len ip address string len.
  * @return 0 on success or < 0 on error.
  */
-static int sqlippool_command(char const * fmt, rlm_sql_handle_t * handle, rlm_sqlippool_t *data, REQUEST *request,
+static int sqlippool_command(char const *fmt, rlm_sql_handle_t **handle,
+                            rlm_sqlippool_t *data, REQUEST *request,
                             char *param, int param_len)
 {
        char query[MAX_QUERY_LEN];
@@ -307,18 +308,17 @@ static int sqlippool_command(char const * fmt, rlm_sql_handle_t * handle, rlm_sq
         */
        sqlippool_expand(query, sizeof(query), fmt, data, param, param_len);
 
-       if (radius_axlat(&expanded, request, query, data->sql_inst->sql_escape_func, data->sql_inst) < 0) {
-               return -1;
-       }
+       if (radius_axlat(&expanded, request, query, data->sql_inst->sql_escape_func, data->sql_inst) < 0) return -1;
 
-       ret = data->sql_inst->sql_query(data->sql_inst, request, &handle, expanded);
+       ret = data->sql_inst->sql_query(data->sql_inst, request, handle, expanded);
        if (ret < 0){
                talloc_free(expanded);
                return -1;
        }
        talloc_free(expanded);
 
-       (data->sql_inst->module->sql_finish_query)(handle, data->sql_inst->config);
+       if (*handle) (data->sql_inst->module->sql_finish_query)(*handle, data->sql_inst->config);
+
        return 0;
 }
 
@@ -327,6 +327,7 @@ static int sqlippool_command(char const * fmt, rlm_sql_handle_t * handle, rlm_sq
  */
 #undef DO
 #define DO(_x) sqlippool_command(inst->_x, handle, inst, request, NULL, 0)
+#define DO_PART(_x) sqlippool_command(inst->_x, &handle, inst, request, NULL, 0)
 
 /*
  * Query the database expecting a single result row
@@ -489,7 +490,7 @@ static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *reque
 
        handle = fr_connection_get(inst->sql_inst->pool);
        if (!handle) {
-               REDEBUG("cannot get sql connection");
+               REDEBUG("Failed reserving SQL connection");
                return RLM_MODULE_FAIL;
        }
 
@@ -508,12 +509,12 @@ static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *reque
        if (inst->last_clear < now) {
                inst->last_clear = now;
 
-               DO(allocate_begin);
-               DO(allocate_clear);
-               DO(allocate_commit);
+               DO_PART(allocate_begin);
+               DO_PART(allocate_clear);
+               DO_PART(allocate_commit);
        }
 
-       DO(allocate_begin);
+       DO_PART(allocate_begin);
 
        allocation_len = sqlippool_query1(allocation, sizeof(allocation),
                                          inst->allocate_find, handle,
@@ -523,7 +524,7 @@ static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *reque
         *      Nothing found...
         */
        if (allocation_len == 0) {
-               DO(allocate_commit);
+               DO_PART(allocate_commit);
 
                /*
                 *Should we perform pool-check ?
@@ -578,7 +579,7 @@ static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *reque
         */
        vp = fr_pair_afrom_num(request->reply, inst->framed_ip_address, 0);
        if (fr_pair_value_from_str(vp, allocation, allocation_len) < 0) {
-               DO(allocate_commit);
+               DO_PART(allocate_commit);
 
                RDEBUG("Invalid IP number [%s] returned from instbase query.", allocation);
                fr_connection_release(inst->sql_inst->pool, handle);
@@ -591,18 +592,18 @@ static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *reque
        /*
         *      UPDATE
         */
-       sqlippool_command(inst->allocate_update, handle, inst, request,
+       sqlippool_command(inst->allocate_update, &handle, inst, request,
                          allocation, allocation_len);
 
-       DO(allocate_commit);
+       DO_PART(allocate_commit);
 
        fr_connection_release(inst->sql_inst->pool, handle);
 
        return do_logging(request, inst->log_success, RLM_MODULE_OK);
 }
 
-static int mod_accounting_start(rlm_sql_handle_t *handle,
-                                     rlm_sqlippool_t *inst, REQUEST *request)
+static int mod_accounting_start(rlm_sql_handle_t **handle,
+                               rlm_sqlippool_t *inst, REQUEST *request)
 {
        DO(start_begin);
        DO(start_update);
@@ -611,8 +612,8 @@ static int mod_accounting_start(rlm_sql_handle_t *handle,
        return RLM_MODULE_OK;
 }
 
-static int mod_accounting_alive(rlm_sql_handle_t *handle,
-                                     rlm_sqlippool_t *inst, REQUEST *request)
+static int mod_accounting_alive(rlm_sql_handle_t **handle,
+                               rlm_sqlippool_t *inst, REQUEST *request)
 {
        DO(alive_begin);
        DO(alive_update);
@@ -620,8 +621,8 @@ static int mod_accounting_alive(rlm_sql_handle_t *handle,
        return RLM_MODULE_OK;
 }
 
-static int mod_accounting_stop(rlm_sql_handle_t *handle,
-                                     rlm_sqlippool_t *inst, REQUEST *request)
+static int mod_accounting_stop(rlm_sql_handle_t **handle,
+                              rlm_sqlippool_t *inst, REQUEST *request)
 {
        DO(stop_begin);
        DO(stop_clear);
@@ -630,8 +631,8 @@ static int mod_accounting_stop(rlm_sql_handle_t *handle,
        return do_logging(request, inst->log_clear, RLM_MODULE_OK);
 }
 
-static int mod_accounting_on(rlm_sql_handle_t *handle,
-                                     rlm_sqlippool_t *inst, REQUEST *request)
+static int mod_accounting_on(rlm_sql_handle_t **handle,
+                            rlm_sqlippool_t *inst, REQUEST *request)
 {
        DO(on_begin);
        DO(on_clear);
@@ -640,8 +641,8 @@ static int mod_accounting_on(rlm_sql_handle_t *handle,
        return RLM_MODULE_OK;
 }
 
-static int mod_accounting_off(rlm_sql_handle_t *handle,
-                                     rlm_sqlippool_t *inst, REQUEST *request)
+static int mod_accounting_off(rlm_sql_handle_t **handle,
+                             rlm_sqlippool_t *inst, REQUEST *request)
 {
        DO(off_begin);
        DO(off_clear);
@@ -657,11 +658,13 @@ static int mod_accounting_off(rlm_sql_handle_t *handle,
  */
 static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
 {
-       int rcode = RLM_MODULE_NOOP;
-       VALUE_PAIR *vp;
-       int acct_status_type;
-       rlm_sqlippool_t *inst = (rlm_sqlippool_t *) instance;
-       rlm_sql_handle_t *handle;
+       int                     rcode = RLM_MODULE_NOOP;
+       VALUE_PAIR              *vp;
+
+       int                     acct_status_type;
+
+       rlm_sqlippool_t         *inst = (rlm_sqlippool_t *) instance;
+       rlm_sql_handle_t        *handle;
 
        vp = fr_pair_find_by_num(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY);
        if (!vp) {
@@ -685,33 +688,31 @@ static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *requ
 
        handle = fr_connection_get(inst->sql_inst->pool);
        if (!handle) {
-               RDEBUG("Cannot allocate sql connection");
+               RDEBUG("Failed reserving SQL connection");
                return RLM_MODULE_FAIL;
        }
 
-       if (inst->sql_inst->sql_set_user(inst->sql_inst, request, NULL) < 0) {
-               return RLM_MODULE_FAIL;
-       }
+       if (inst->sql_inst->sql_set_user(inst->sql_inst, request, NULL) < 0) return RLM_MODULE_FAIL;
 
        switch (acct_status_type) {
        case PW_STATUS_START:
-               rcode = mod_accounting_start(handle, inst, request);
+               rcode = mod_accounting_start(&handle, inst, request);
                break;
 
        case PW_STATUS_ALIVE:
-               rcode = mod_accounting_alive(handle, inst, request);
+               rcode = mod_accounting_alive(&handle, inst, request);
                break;
 
        case PW_STATUS_STOP:
-               rcode = mod_accounting_stop(handle, inst, request);
+               rcode = mod_accounting_stop(&handle, inst, request);
                break;
 
        case PW_STATUS_ACCOUNTING_ON:
-               rcode = mod_accounting_on(handle, inst, request);
+               rcode = mod_accounting_on(&handle, inst, request);
                break;
 
        case PW_STATUS_ACCOUNTING_OFF:
-               rcode = mod_accounting_off(handle, inst, request);
+               rcode = mod_accounting_off(&handle, inst, request);
                break;
        }
 
index 7d3719a..203576c 100644 (file)
@@ -7,3 +7,4 @@ dictionary
 test.conf
 radius.log
 radiusd.pid
+eapol_test
diff --git a/src/tests/keywords/case-attr-error b/src/tests/keywords/case-attr-error
new file mode 100644 (file)
index 0000000..e9516cc
--- /dev/null
@@ -0,0 +1,20 @@
+# PRE: case-empty
+#
+update reply {
+       Filter-Id := "fail"
+}
+
+switch &reply:Filter-Id {
+       # deliberately empty
+       case "filter" {
+       }
+
+       case &Not-Dynamically-Allocated {       # ERROR
+               update reply {
+                       Filter-Id := "fail"
+               }
+       }
+
+       case {
+       }
+}
diff --git a/src/tests/keywords/regex-escape b/src/tests/keywords/regex-escape
new file mode 100644 (file)
index 0000000..4ab1e5b
--- /dev/null
@@ -0,0 +1,29 @@
+#
+#  PRE: update if
+#
+
+#
+#  Strings which are expanded in a regex have regex special
+#  characters escaped.  Because the input strings are unsafe.
+#
+update request {
+       Tmp-String-0 := "example.com"
+       Tmp-String-1 := "exampleXcom"
+}
+
+if ("exampleXcom" =~ /%{Tmp-String-0}/) {
+       update reply {
+               Filter-Id := "fail 1"
+       }
+}
+
+elsif (&Tmp-String-1 =~ /%{Tmp-String-0}/) {
+       update reply {
+               Filter-Id := "fail 2"
+       }
+}
+else {
+       update reply {
+               Filter-Id := "filter"
+       }
+}
\ No newline at end of file
diff --git a/src/tests/keywords/regex-lhs b/src/tests/keywords/regex-lhs
new file mode 100644 (file)
index 0000000..91b0b20
--- /dev/null
@@ -0,0 +1,27 @@
+#
+#  PRE: update if regex-escape
+#
+
+#
+#  Strings which are expanded in a regex have regex special
+#  characters escaped.  Because the input strings are unsafe.
+#
+update request {
+       Tmp-String-0 := "example.com"
+       Tmp-String-1 := "^foo$bar"
+}
+
+if (&Tmp-String-0 !~ /example\.com$/) {
+       update reply {
+               Filter-Id := "fail 1"
+       }
+}
+elsif (&Tmp-String-1 !~ /\^foo\$bar/) {
+       update reply {
+               Filter-Id := "fail 1"
+       }
+} else {
+       update reply {
+               Filter-Id := "filter"
+       }
+}
\ No newline at end of file
diff --git a/src/tests/keywords/string b/src/tests/keywords/string
new file mode 100644 (file)
index 0000000..bcf0fcf
--- /dev/null
@@ -0,0 +1,19 @@
+#
+#  PRE: cmp
+#
+update control {
+       Cleartext-Password := 'hello'
+}
+
+update request {
+       Tmp-String-0 := "this\000is\000a\000string"
+}
+
+#
+#  %{string:...} is explicitly not binary safe
+#
+if ("%{string:Tmp-String-0}" == "this") {
+       update reply {
+               Filter-Id := "filter"
+       }
+}
diff --git a/src/tests/keywords/update-filter b/src/tests/keywords/update-filter
new file mode 100644 (file)
index 0000000..30f96be
--- /dev/null
@@ -0,0 +1,75 @@
+#
+#  PRE: update
+#
+update control {
+       Tmp-Integer-0 := 5
+       Tmp-Integer-0 += 10
+       Tmp-Integer-0 += 15
+       Tmp-Integer-0 += 20
+       Tmp-String-0 := 'foo'
+       Tmp-String-0 += 'baz'
+       Tmp-String-0 += 'boink'
+}
+
+#
+#  Reset the request list
+#
+update {
+       &request: !* ANY
+       &request: += &control:[*]
+}
+
+debug_request
+
+#
+#  Only matching attributes of the specified type should remain
+#
+update request {
+       &Tmp-Integer-0 == 10
+}
+
+if (&Tmp-Integer-0[0] != 10) {
+       update reply {
+               Filter-Id += "fail 1"
+       }
+}
+
+if ("%{Tmp-Integer-0[#]}" != 1) {
+       update reply {
+               Filter-Id += "fail 2"
+       }
+}
+
+if ("%{Tmp-String-0[#]}" != 3) {
+       update reply {
+               Filter-Id += "fail 3"
+       }
+}
+
+debug_request
+
+#
+#  Only matching attributes of the specified type should remain
+#
+update request {
+       &Tmp-String-0 == 'baz'
+}
+
+if (&Tmp-String-0[0] != 'baz') {
+       update reply {
+               Filter-Id += "fail 4"
+       }
+}
+
+if ("%{Tmp-String-0[#]}" != 1) {
+       update reply {
+               Filter-Id += "fail 5"
+       }
+}
+
+update {
+       control:Auth-Type := Accept
+       reply:Filter-Id := "filter"
+}
+
+debug_request
index 886e6b2..7474489 100644 (file)
@@ -1,6 +1,7 @@
 MAP_TESTS      := $(patsubst $(top_srcdir)/src/tests/map/%,%,$(filter-out %.conf %.md %.attrs %.c %.mk %~ %.rej %.out,$(wildcard $(top_srcdir)/src/tests/map/*)))
 MAP_OUTPUT     := $(addsuffix .out,$(addprefix $(BUILD_DIR)/tests/map/,$(MAP_TESTS)))
-MAP_UNIT       := $(BUILD_DIR)/bin/local/map_unit
+MAP_UNIT_BIN   := $(BUILD_DIR)/bin/local/map_unit
+MAP_UNIT       := ./build/make/jlibtool --silent --mode=execute $(MAP_UNIT_BIN)
 
 .PHONY: $(BUILD_DIR)/tests/map/
 $(BUILD_DIR)/tests/map/:
@@ -11,7 +12,7 @@ $(BUILD_DIR)/tests/map/:
 #
 #      Create the output directory before the files
 #
-$(MAP_OUTPUT): $(MAP_UNIT) | $(BUILD_DIR)/tests/map/
+$(MAP_OUTPUT): $(MAP_UNIT_BIN) | $(BUILD_DIR)/tests/map/
 
 #
 #      Re-run the tests if the input file changes
diff --git a/src/tests/modules/sql/README b/src/tests/modules/sql/README
deleted file mode 100644 (file)
index b5e79e2..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-All SQL related tests should be defined here and the driver specific directory need only have links to the tests defined here.
-
-All User-Name attributes, Acct-Session-Id, and Acct-Multi-Session-Id attributes
-
-       MUST BE UNIQUE FOR EVERY TEST.
-
-Otherwise the tests will stomp on each other when run in parallel.
index 7333d3e..ecf5e06 100644 (file)
@@ -4,3 +4,4 @@ SOURCES := rbmonkey.c
 
 TGT_PREREQS    := libfreeradius-radius.a
 TGT_LDLIBS     := $(LIBS)
+TGT_INSTALLDIR :=
index f7d055c..bbe24d2 100644 (file)
@@ -203,7 +203,7 @@ data <ipv4prefix>&Framed-IP-Address <= 192.168.0.0/16
 
 # All IP address literals should be parsed as prefixes
 condition Framed-IP-Address <= 192.168.0.0/16
-data &Framed-IP-Address <= 192.168.0.0/16
+data <ipv4prefix>&Framed-IP-Address <= 192.168.0.0/16
 
 # string attributes must be string
 condition User-Name == "bob"
@@ -621,10 +621,10 @@ condition &Attr-1 == 'bar'
 data &User-Name == 'bar'
 
 condition &Vendor-11344-Attr-1 == 127.0.0.1
-data &FreeRADIUS-Proxied-To == 127.0.0.1/32
+data &FreeRADIUS-Proxied-To == 127.0.0.1
 
 condition &FreeRADIUS-Attr-1 == 127.0.0.1
-data &FreeRADIUS-Proxied-To == 127.0.0.1/32
+data &FreeRADIUS-Proxied-To == 127.0.0.1
 
 #
 #  Escape the backslashes correctly
@@ -662,3 +662,18 @@ data <ipv4prefix>&NAS-IP-Address == 192.168.0.0/24
 
 condition <ipv4prefix>192.168.0.0/24 > &NAS-IP-Address
 data <ipv4prefix>192.168.0.0/24 > &NAS-IP-Address
+
+#
+#  We add casts to the LHS if necessary
+#
+condition &NAS-IP-Address < &PMIP6-Home-IPv4-HoA
+data <ipv4prefix>&NAS-IP-Address < &PMIP6-Home-IPv4-HoA
+
+condition &NAS-IP-Address < 192.168/16
+data <ipv4prefix>&NAS-IP-Address < 192.168.0.0/16
+
+condition &NAS-IP-Address < "%{echo: 192.168/16}"
+data <ipv4prefix>&NAS-IP-Address < "%{echo: 192.168/16}"
+
+condition &NAS-IP-Address < `/bin/echo 192.168/16`
+data <ipv4prefix>&NAS-IP-Address < `/bin/echo 192.168/16`
index 0864784..801b501 100644 (file)
@@ -8,7 +8,7 @@ decode 01 01 00
 data rad_attr2vp: Insufficient data
 
 encode Attr-26.1.256 = 0x00000001
-data Invalid OID
+data Number '256' out of allowed range in attribute identifier
 
 encode Attr-240.1 = 0x01
 data Standard attributes cannot use OIDs
index d89b174..0024794 100644 (file)
@@ -120,6 +120,9 @@ data Framed-IP-Address = 0.0.0.0
 attribute Framed-IP-Address = 127
 data Framed-IP-Address = 0.0.0.127
 
+attribute Framed-IP-Address = 127.0
+data Framed-IP-Address = 127.0.0.0
+
 attribute Framed-IPv6-Prefix = ::1
 data Framed-IPv6-Prefix = ::1/128
 
@@ -135,6 +138,46 @@ data Framed-IPv6-Prefix = 11:22:33:44:55:66:77:88/128
 attribute Framed-IPv6-Prefix = *
 data Framed-IPv6-Prefix = ::/128
 
+attribute PMIP6-Home-IPv4-HoA = 127/8
+data PMIP6-Home-IPv4-HoA = 127.0.0.0/8
+
+attribute PMIP6-Home-IPv4-HoA = 127/8
+data PMIP6-Home-IPv4-HoA = 127.0.0.0/8
+
+#
+#  Octets outside of the mask are OK, but
+#  are mashed to zero.
+#
+attribute PMIP6-Home-IPv4-HoA = 127.63/8
+data PMIP6-Home-IPv4-HoA = 127.0.0.0/8
+
+#
+#  Unless you give a good mask.
+#
+attribute PMIP6-Home-IPv4-HoA = 127.63/16
+data PMIP6-Home-IPv4-HoA = 127.63.0.0/16
+
+attribute PMIP6-Home-IPv4-HoA = 127.999/16
+data Failed to parse IPv4 address string "127.999/16"
+
+attribute PMIP6-Home-IPv4-HoA = 127.bob/16
+data Failed to parse IPv4 address string "127.bob/16"
+
+attribute PMIP6-Home-IPv4-HoA = 127.63/15
+data PMIP6-Home-IPv4-HoA = 127.62.0.0/15
+
+attribute PMIP6-Home-IPv4-HoA = 127.63.1/24
+data PMIP6-Home-IPv4-HoA = 127.63.1.0/24
+
+attribute PMIP6-Home-IPv4-HoA = 127.63.1.6
+data PMIP6-Home-IPv4-HoA = 127.63.1.6/32
+
+attribute PMIP6-Home-IPv4-HoA = 256/8
+data Failed to parse IPv4 address string "256/8"
+
+attribute PMIP6-Home-IPv4-HoA = bob/8
+data Failed to parse IPv4 address string "bob/8"
+
 $INCLUDE tunnel.txt
 $INCLUDE errors.txt
 $INCLUDE extended.txt
index b6485f2..6bde677 100644 (file)
@@ -1,5 +1,5 @@
 Name:         freeradius-server
-Version: 3.0.10
+Version: 3.0.12
 Release:      0
 License:      GPLv2 ; LGPLv2.1
 Group:        Productivity/Networking/Radius/Servers